I am receiving incompatible pointer type everywhere when I am trying to work with unicode LPCWSTR types.
I am completely stuck no matter what I do, tried to search for a answer lots of times and still no hope!
My code:
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "Mouse.h"
#include "Keyboard.h"
//#define APP_WindowClassName "MOUSE_CLICKER"
//#define APP_WindowTitle "Mouse Clicker"
LRESULT CALLBACK app_WindowProcedure (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Arg1 - A handle to the current instance of the application, Arg 2 - ???, Arg 3 - Arguments, Arg 4 - Controls how the window is to be shown.
WNDCLASSEXW main_WindowClass = { };
main_WindowClass.cbSize = sizeof(WNDCLASSEXA);
main_WindowClass.cbClsExtra = 0;
main_WindowClass.cbWndExtra = 0;
main_WindowClass.hInstance = hInstance;
main_WindowClass.lpfnWndProc = app_WindowProcedure;
main_WindowClass.lpszClassName = TEXT("MOUSE_CLICKER");
main_WindowClass.lpszMenuName = NULL;
main_WindowClass.hbrBackground = (HBRUSH) (TEXT(COLOR_BACKGROUND));
main_WindowClass.hCursor = LoadCursorW (NULL, TEXT(IDC_ARROW));
main_WindowClass.hIcon = LoadIconW(NULL, TEXT(IDI_APPLICATION));
main_WindowClass.hIconSm = LoadIconW(NULL, TEXT(IDI_APPLICATION));
main_WindowClass.style = CS_DBLCLKS;
//CS_HREDRAW | CS_VREDRAW a
if (RegisterClassExW(&main_WindowClass) == 0) {
printf ("[CRITICAL] main_WindowClass cannot be registered!");
return -1;
}
HWND main_WindowHandle = CreateWindowExW (0, TEXT("MOUSE_CLICKER"), TEXT("MouseClicker"), WS_OVERLAPPEDWINDOW, 0, 0, 800, 600, NULL, NULL, hInstance, NULL);
if (main_WindowHandle == NULL) {
return -1;
}
ShowWindow(main_WindowHandle, nCmdShow);
printf("Unicode: %d", IsWindowUnicode(main_WindowHandle));
MSG ProcessingMessage;
while (GetMessage(&ProcessingMessage, NULL, 0, 0)) {
TranslateMessage(&ProcessingMessage);
DispatchMessage(&ProcessingMessage);
}
return ProcessingMessage.wParam;
}
My build log picture link:
PS: I am a beginner in C (still learning) and understandable descriptive information on what I am doing wrong would be nice.
PS2: To avoid confusion this is pure C, NOT C++.
Solution code:
#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include "Mouse.h"
#include "Keyboard.h"
LRESULT CALLBACK app_WindowProcedure (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Arg1 - A handle to the current instance of the application, Arg 2 - ???, Arg 3 - Arguments, Arg 4 - Controls how the window is to be shown.
WNDCLASSEXW main_WindowClass = { };
main_WindowClass.cbSize = sizeof(WNDCLASSEXA);
main_WindowClass.cbClsExtra = 0;
main_WindowClass.cbWndExtra = 0;
main_WindowClass.hInstance = hInstance;
main_WindowClass.lpfnWndProc = app_WindowProcedure;
main_WindowClass.lpszClassName = L"MOUSE_CLICKER";
main_WindowClass.lpszMenuName = NULL;
main_WindowClass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND);
main_WindowClass.hCursor = LoadCursorW (NULL, (LPCWSTR) IDC_ARROW);
main_WindowClass.hIcon = LoadIconW(NULL, (LPCWSTR) IDI_APPLICATION);
main_WindowClass.hIconSm = LoadIconW(NULL, (LPCWSTR) IDI_APPLICATION);
main_WindowClass.style = CS_DBLCLKS;
//CS_HREDRAW | CS_VREDRAW a
if (RegisterClassExW(&main_WindowClass) == 0) {
printf ("[CRITICAL] main_WindowClass cannot be registered!");
return -1;
}
HWND main_WindowHandle = CreateWindowExW (0, L"MOUSE_CLICKER", L"MouseClicker", WS_OVERLAPPEDWINDOW, 0, 0, 800, 600, NULL, NULL, hInstance, NULL);
if (main_WindowHandle == NULL) {
return -1;
}
ShowWindow(main_WindowHandle, nCmdShow);
printf("Unicode: %d", IsWindowUnicode(main_WindowHandle));
MSG ProcessingMessage;
while (GetMessage(&ProcessingMessage, NULL, 0, 0)) {
TranslateMessage(&ProcessingMessage);
DispatchMessage(&ProcessingMessage);
}
return ProcessingMessage.wParam;
}
Define UNICODE in your project.
Based on whether UNICODE is defined, TEXT expands to either LPSTR or LPWSTR. You are explicitly calling *W versions of WinAPI functions but pass LPSTR instead of LPWSTR. Prefixing string literal with L should work actually. Maybe you used it as L("foo") - it won't work this way. You need to use L"foo".
Overall, if you use TEXT, you should use WinAPI functions without suffixes, so that code will compile both with and without UNICODE defined. If you explicitly use *W functions, use L"" strings.
There are several approaches you can take to get this to work; since you're already going down the path of using Generic-Text Mappings in Tchar.h, let's continue on that route.
Here is the main body of your program, revised to run as Unicode when your project is set to build Unicode.
(A side "benefit", if you would call it that, is that you can run your application as an ASCII application as well just by changing the character set of the project.)
LRESULT CALLBACK app_WindowProcedure(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // Arg1 - A handle to the current instance of the application, Arg 2 - ???, Arg 3 - Arguments, Arg 4 - Controls how the window is to be shown.
WNDCLASSEX main_WindowClass = {};
main_WindowClass.cbSize = sizeof(WNDCLASSEX);
main_WindowClass.cbClsExtra = 0;
main_WindowClass.cbWndExtra = 0;
main_WindowClass.hInstance = hInstance;
main_WindowClass.lpfnWndProc = app_WindowProcedure;
main_WindowClass.lpszClassName = TEXT("MOUSE_CLICKER");
main_WindowClass.lpszMenuName = NULL;
main_WindowClass.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
main_WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
main_WindowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
main_WindowClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
main_WindowClass.style = CS_DBLCLKS;
//CS_HREDRAW | CS_VREDRAW a
if (RegisterClassEx(&main_WindowClass) == 0) {
_tprintf(TEXT("[CRITICAL] main_WindowClass cannot be registered!"));
return -1;
}
HWND main_WindowHandle = CreateWindowEx(0, TEXT("MOUSE_CLICKER"), TEXT("MouseClicker"), WS_OVERLAPPEDWINDOW, 0, 0, 800, 600, NULL, NULL, hInstance, NULL);
if (main_WindowHandle == NULL) {
return -1;
}
ShowWindow(main_WindowHandle, nCmdShow);
_tprintf(TEXT("Unicode: %d"), IsWindowUnicode(main_WindowHandle));
MSG ProcessingMessage;
while (GetMessage(&ProcessingMessage, NULL, 0, 0)) {
TranslateMessage(&ProcessingMessage);
DispatchMessage(&ProcessingMessage);
}
return ProcessingMessage.wParam;
}
Note that Unicode-specific function calls were replaced with their generic counterparts (e.g., DefWindowProcW() is now DefWindowProc(); RegisterClassExW() is now RegisterClassEx(); printf() is now _tprintf(), and so on). All text is wrapped in the TEXT() macro.
An alternative approach, as you worked in part, is to make all API calls the ...W versions for Unicode functions, and to hard-code text using the L prefix to use Unicode text.
A good rule of thumb is to try to pick one technique or another, and apply it consistently and across the board.
This should work
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "Mouse.h"
#include "Keyboard.h"
//#define APP_WindowClassName "MOUSE_CLICKER"
//#define APP_WindowTitle "Mouse Clicker"
LRESULT CALLBACK app_WindowProcedure(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Arg1 - A handle to the current instance of the application, Arg 2 - ???, Arg 3 - Arguments, Arg 4 - Controls how the window is to be shown.
WNDCLASSEXW main_WindowClass = *((WNDCLASSEXW*)malloc(sizeof(WNDCLASSEXW)));
main_WindowClass.cbSize = sizeof(WNDCLASSEXA);
main_WindowClass.cbClsExtra = 0;
main_WindowClass.cbWndExtra = 0;
main_WindowClass.hInstance = hInstance;
main_WindowClass.lpfnWndProc = app_WindowProcedure;
main_WindowClass.lpszClassName = L"MOUSE_CLICKER";
main_WindowClass.lpszMenuName = NULL;
main_WindowClass.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
main_WindowClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
main_WindowClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
main_WindowClass.hIconSm = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
main_WindowClass.style = CS_DBLCLKS;
//CS_HREDRAW | CS_VREDRAW a
if (RegisterClassExW(&main_WindowClass) == 0) {
printf("[CRITICAL] main_WindowClass cannot be registered!");
return -1;
}
HWND main_WindowHandle = CreateWindowExW(0, L"MOUSE_CLICKER", L"MouseClicker", WS_OVERLAPPEDWINDOW, 0, 0, 800, 600, NULL, NULL, hInstance, NULL);
if (main_WindowHandle == NULL) {
return -1;
}
ShowWindow(main_WindowHandle, nCmdShow);
printf("Unicode: %d", IsWindowUnicode(main_WindowHandle));
MSG ProcessingMessage;
while (GetMessage(&ProcessingMessage, NULL, 0, 0)) {
TranslateMessage(&ProcessingMessage);
DispatchMessage(&ProcessingMessage);
}
return ProcessingMessage.wParam;
}
Related
Question:
I am trying to set up the Winapi with C to display a simple window with the bare minimum of code, how do I do that in the way that my source code is formatted?
Issue:
The following does not open a window, it simply closes, why is this?
/* window_s.h */
typedef struct {
WNDCLASS wc;
HINSTANCE hInstance;
HWND hwnd;
} WINDOW;
/* setUpWinProc.h */
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) { }
/* registerWindow.c */
void registerWindow(WINDOW *window) {
const char CLASS_NAME[]
= "Window Class Name";
window->wc.lpfnWndProc = WindowProc;
window->wc.hInstance = window->wc.hInstance;
window->wc.lpszClassName = CLASS_NAME;
RegisterClass(&(window->wc));
}
/* createWindow.c */
int_fast64_t CreateWindow_(WINDOW *window) {
window->hwnd = CreateWindowEx(
0, // Optional window styles
window->wc.lpszClassName, // Window class
"Window", // Window text
WS_OVERLAPPEDWINDOW, //Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
window->hInstance, // Instance handle
NULL // Additional application data
);
if (window->hwnd == NULL)
return 0;
return window->hwnd;
}
/* Window_Main.c */
#include <windows.h>
#include "window_s.h"
#include "setUpWinProc.h"
#include "registerWindow.c"
#include "createWindow.c"
#include <stdio.h>
int WINAPI WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pCmdLine,
int nCmdShow ) {
WINDOW window = {{}, hInstance};
registerWindow(&window);
CreateWindow_(&window);
ShowWindow(window.hwnd, nCmdShow);
}
This is part of the issue:
int WINAPI WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pCmdLine,
int nCmdShow ) {
WINDOW window = {{}, hInstance};
registerWindow(&window);
CreateWindow_(&window);
ShowWindow(window.hwnd, nCmdShow);
}
What do you think happens after ShowWindow returns and WinMain itself returns? (Hint: the program exits).
Extend your WinMain to pump messages with TranslateMessage+DispatchMessage.
int WINAPI WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pCmdLine,
int nCmdShow ) {
MSG msg;
WINDOW window = {{}, hInstance};
registerWindow(&window);
CreateWindow_(&window);
ShowWindow(window.hwnd, nCmdShow);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Then your message proc needs to handle WM_CLOSE and WM_PAINT as a minimum and be able to forward to the default window proc for messages it doesn't handle.
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) {
switch (uMsg) {
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
default: {
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
return 0;
}
Your RegisterClass call looks suspicous as well. Let's initialize like this:
WNDCLASSEXW wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszClassName = szWindowClass;
RegisterClassExW(&wcex);
If you have Visual Studio (and edition), there's a default Win32 application that generates the most minimal of stub applications that does exactly what you are trying to achieve. Look for the C++ project for "Default Windows Application" or similar.
The core issue is here:
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) { }
As the compiler warned, this function needs to return a value (but isn't). The behavior of registering this as a window procedure is undefined. It will probably fail to create a window; CreateWindowEx() calls into the window procedure with WM_NCCREATE and WM_CREATE messages before it returns. Either message handler must return a particular value to continue window creation.
There's a similar issue with the window class name: It's using a local variable, but passes a pointer to it out. As registerWindow() returns, CLASS_NAME is gone. Class registration succeeds, but when it comes time to create the window, the call to CreateWindowEx() uses garbage as the window class name.
The first fix is thus:
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) {
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
and
void registerWindow(WINDOW *window) {
static const char CLASS_NAME[] = "Window Class Name";
// ...
}
That solves the window creation, though you won't see the window for long (if at all) because the code immediately falls out of WinMain() (which also needs to return a value), causing the process to terminate.
To fix that, you'll have to dispatch messages on the thread that created the window. The following will address both of these issues:
int WINAPI WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pCmdLine,
int nCmdShow ) {
WINDOW window = {{}, hInstance};
registerWindow(&window);
CreateWindow_(&window);
ShowWindow(window.hwnd, nCmdShow);
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
return msg.wParam;
}
That's the bare minimum required (unless you count MessageBox() as "getting a window to open"). But it won't allow you to exit the application. To add that functionality, you'll want to add a WM_DESTROY handler that will signal the message loop to end, like so:
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg, WPARAM wParam,
LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
In one of my projects, I need to create a window in a non-main thread. I have never done that so I don't much experience on that.
According to the MSDN documentation and the SO question, I should be able to create a window in other thread, but I cannot succeed. Even though, in thread start routine, I register a window class, create a window and provide a message loop, the thread starts and exits immediately. In addition, I cannot debug the thread start routine so I cannot hit the break points inside it.
Is there something I am missing? I hope I don't miss anything silly.
Please consider the following demo. Thank you for taking your time.
#include <Windows.h>
#include <tchar.h>
HANDLE hThread;
DWORD WINAPI OtherUIThreadFunc(LPVOID args);
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND m_hwnd;
MSG msg;
WNDCLASSEX m_wcx;
const int MESSAGE_PROCESSED = 0;
const TCHAR* m_szClassName = _T("DemoWndCls");
const TCHAR* m_szWindowTitle = _T("Demo Window");
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nCmdShow)
{
hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)OtherUIThreadFunc, hInstance, 0, NULL);
/*MSG msg;
ZeroMemory(&m_wcx, sizeof(m_wcx));
m_wcx.cbSize = sizeof(m_wcx);
m_wcx.style = CS_VREDRAW | CS_HREDRAW;
m_wcx.hInstance = hInstance;
m_wcx.lpszClassName = m_szClassName;
m_wcx.lpfnWndProc = WndProc;
m_wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
m_wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
m_wcx.hbrBackground = (HBRUSH)COLOR_WINDOW;
if (!RegisterClassEx(&m_wcx))
return false;
m_hwnd = CreateWindowEx(0, m_wcx.lpszClassName, m_szWindowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 480, 360, NULL, NULL, hInstance, NULL);
if (!m_hwnd)
return false;
ShowWindow(m_hwnd, SW_NORMAL);
UpdateWindow(m_hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;*/
}
DWORD WINAPI OtherUIThreadFunc(LPVOID args)
{
HINSTANCE hInstance = (HINSTANCE)args;
ZeroMemory(&m_wcx, sizeof(m_wcx));
m_wcx.cbSize = sizeof(m_wcx);
m_wcx.style = CS_VREDRAW | CS_HREDRAW;
m_wcx.hInstance = hInstance;
m_wcx.lpszClassName = m_szClassName;
m_wcx.lpfnWndProc = WndProc;
m_wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
m_wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
m_wcx.hbrBackground = (HBRUSH)COLOR_WINDOW;
if (!RegisterClassEx(&m_wcx))
return false;
m_hwnd = CreateWindowEx(0, m_wcx.lpszClassName, m_szWindowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 480, 360, NULL, NULL, hInstance, NULL);
if (!m_hwnd)
return false;
ShowWindow(m_hwnd, SW_NORMAL);
UpdateWindow(m_hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
return MESSAGE_PROCESSED;
case WM_DESTROY:
PostQuitMessage(0);
return MESSAGE_PROCESSED;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
Window creation succeeds (in theory, anyway). The issue is that the primary thread moves one to return, which causes the runtime to terminate the process.
To solve the issue you will have to keep the primary thread alive. A call to WaitForSingleObject, or a message loop are possible options.
This is mostly a result of following the conventions of C and C++. In either case returning from the main function is equivalent to calling the exit() function. This explains why returning from the primary thread tears down the entire process.
Bonus reading: If you return from the main thread, does the process exit?
I tried to create a single button in a 500x500 window, the problem is, the button does not appear in the windows, and clicking the windows alone triggers the procedure/handler for the button:
#include <windows.h>
LRESULT CALLBACK MainWindowHandler(HWND obj, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ButtonHandler(HWND obj, UINT msg, WPARAM wParam, LPARAM lParam);
LPCSTR FrameClassName = "MainWindow";
LPCSTR ButtonClassName = "Button";
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX Frame;
HWND FrameHandle;
WNDCLASSEX Button;
HWND ButtonHandle;
MSG Msg;
Frame.cbSize = sizeof(WNDCLASSEX);
Frame.style = 0;
Frame.lpfnWndProc = MainWindowHandler;
Frame.cbClsExtra = 0;
Frame.cbWndExtra = 0;
Frame.hInstance = hInstance;
Frame.hIcon = LoadIcon(NULL, IDI_APPLICATION);
Frame.hCursor = LoadCursor(NULL, IDC_ARROW);
Frame.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
Frame.lpszMenuName = NULL;
Frame.lpszClassName = FrameClassName;
Frame.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
Button.cbSize = sizeof(WNDCLASSEX);
Button.style = 0;
Button.lpfnWndProc = ButtonHandler;
Button.cbClsExtra = 0;
Button.cbWndExtra = 0;
Button.hInstance = hInstance;
Button.hIcon = LoadIcon(NULL, IDI_APPLICATION);
Button.hCursor = LoadCursor(NULL, IDC_ARROW);
Button.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
Button.lpszMenuName = FrameClassName;
Button.lpszClassName = ButtonClassName;
Button.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&Frame))
{
MessageBox(NULL,"Registration Failure","ERROR",MB_ICONWARNING| MB_OK);
return 0;
}
if(!RegisterClassEx(&Button))
{
MessageBox(NULL,"Registration Failure","ERROR",MB_ICONWARNING| MB_OK);
return 0;
}
FrameHandle = CreateWindowEx(WS_EX_CLIENTEDGE,
FrameClassName,
"Application",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 500,
NULL, NULL, hInstance, NULL);
ButtonHandle = CreateWindowEx(0, ButtonClassName, "My Button",
WS_CHILD | WS_VISIBLE, 250, 250, 30, 20, FrameHandle,
(HMENU)FrameHandle, hInstance, NULL);
SendDlgItemMessage(ButtonHandle, 12, WM_SETFONT,
(WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
ShowWindow(FrameHandle, nCmdShow);
UpdateWindow(FrameHandle);
ShowWindow(ButtonHandle, nCmdShow);
UpdateWindow(ButtonHandle);
while(GetMessage(&Msg,NULL,0,0)>0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
LRESULT CALLBACK MainWindowHandler(HWND obj, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
MessageBox(obj,"CLICKED!","BUTTON",0);
break;
case WM_CLOSE:
DestroyWindow(obj);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(obj, msg, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ButtonHandler(HWND obj, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(obj);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(obj, msg, wParam, lParam);
}
return 0;
}
What did i miss?
That is not how you create a button.
A button control uses a special window class, pre-defined by the common controls library. You don't need to register the window class, it is already registered. Recommended reading on using common controls is here on MSDN.
All you need is the call to CreateWindow, just make sure you use the correct class name: WC_BUTTON (which is defined by the common controls header file to be "BUTTON").
For controls, you also generally want to include the WS_TABSTOP style, and for a button specifically, you need to include one of the button styles—e.g., BS_DEFPUSHBUTTON or BS_PUSHBUTTON.
Finally, you're passing the wrong value for the hMenu parameter when you call CreateWindow. For child windows (like controls), this is a unique identifier of the control, not the handle of its parent window. If it's the first control, you might give it an ID of 1. It's best to use constants in your code for this so that you can interact with the controls later programmatically.
#include <CommCtrl.h> // somewhere at the top of your code file
ButtonHandle = CreateWindowEx(0,
WC_BUTTON,
"My Button",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
250, 250, 30, 20,
FrameHandle,
(HMENU)1, // or some other unique ID for this ctrl
hInstance,
NULL);
And since you've included the WS_VISIBLE style, you don't need this code (and you probably should not use nCmdShow with your child windows anyway):
// unnecessary code:
ShowWindow(ButtonHandle, nCmdShow);
UpdateWindow(ButtonHandle);
Finally, I can't help but notice that you're using ANSI string literals. All Windows applications today should be built with Unicode support, which requires that you use wide string literals. To get those, prefix each of them with an L and use the LPCWSTR type: LPCWSTR FrameClassName = L"MainWindow"; Not doing so should have been generating a compiler error; the default settings for a new project define the UNICODE preprocessor symbol. If that's not done for your project, you should do it now.
When creating button with visual style under Windows XP, you need to load comctl32.dll.
#include <CommCtrl.h> // somewhere at the top of your code file
#pragma comment(lib, "Comctl32.lib") // if necessary
// create manifest to use XP visual style
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
// before creating button call:
InitCommonControls(); // necessary to enable Visual style on WinXP
I want to catch message of WM_DEVICECHANGE.But, there is a problem which i can not understand.I want to see when usb or cd inserted.Maybe my notification filter is wrong.
I m using radstudio and the language of its c,also its commandline application.I think everything is obvious in code.What am i doing wrong,i created window for only getting messages.Also i did not understand how it message going to WndProc from message loop.
#pragma hdrstop
#pragma argsused
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <dbt.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch (uiMsg)
{
case WM_DEVICECHANGE:
{
MessageBox(0,"a","b",1);
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
BOOL bRet;
HANDLE a;
HWND lua;
HANDLE hInstance;
MSG msg;
WNDCLASSEX wndClass;
HANDLE hVolNotify;
DEV_BROADCAST_DEVICEINTERFACE dbh;
DEV_BROADCAST_VOLUME NotificationFilter;
lua = CreateWindow("lua", NULL, WS_MINIMIZE, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
wndClass.lpfnWndProc = WndProc;
ZeroMemory(&NotificationFilter, sizeof (NotificationFilter));
NotificationFilter.dbcv_size = sizeof (NotificationFilter);
NotificationFilter.dbcv_devicetype = DBT_DEVTYP_VOLUME;
a = RegisterDeviceNotification(lua,&NotificationFilter,DEVICE_NOTIFY_WINDOW_HANDLE);
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
MessageBox(0,"o","b",1);
if (bRet == -1)
{
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
What am i doing wrong,i created window for only getting messages.
You are asking CreateWindow() to create a window of class "lua" but you have not actually registered the "lua" class via RegisterClass/Ex() before calling CreateWindow(), and you are not checking to see if CreateWindow() returns a NULL window handle on failure.
Also i did not understand how it message going to WndProc from message loop.
That is handled by DispatchMessage(). You need to assign wndClass.lpfnWndProc and register it with RegisterClass() before calling CreateWindow(). Afterwards, when DispatchMessage() sees a message that targets the window created by CreateWindow(), it knows that WndProc() has been associated with that window and will call it directly, passing it the message.
Try this instead:
#pragma hdrstop
#pragma argsused
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <dbt.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
if (uiMsg == WM_DEVICECHANGE)
{
MessageBox(NULL, TEXT("WM_DEVICECHANGE"), TEXT("WndProc"), MB_OK);
return 0;
}
return DefWindowProc(hWnd, uiMsg, wParam, lParam);
}
int _tmain(int argc, _TCHAR* argv[])
{
HINSTANCE hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(NULL));
WNDCLASS wndClass = {0};
wndClass.lpfnWndProc = &WndProc;
wndClass.lpszClassName = TEXT("lua");
wndClass.hInstance = hInstance;
if (RegisterClass(&wndClass))
{
HWND lua = CreateWindow(wndClass.lpszClassName, NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (lua != NULL)
{
DEV_BROADCAST_VOLUME NotificationFilter = {0};
NotificationFilter.dbcv_size = sizeof(NotificationFilter);
NotificationFilter.dbcv_devicetype = DBT_DEVTYP_VOLUME;
HDEVNOTIFY hVolNotify = RegisterDeviceNotification(lua, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
if (hVolNotify != NULL)
{
MSG msg;
while( GetMessage(&msg, NULL, 0, 0) > 0 )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnregisterDeviceNotification(hVolNotify);
}
DestroyWindow(lua);
}
UnregisterClass(wndClass.lpszClassName, hInstance);
}
return 0;
}
For added measure, you can use CreateWindowEx() instead of CreateWindow() to create a message-only window instead, if desired:
HWND lua = CreateWindowEx(0, wndClass.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
You need to set the dbcv_unitmask field of the DEV_BROADCAST_VOLUME structure to indicate which drive letters you're interested in. If you want to see media changes you also need to set the DBTF_MEDIA flag in the dbcv_flags field.
I need to make a few programs in C and i cannot get the window to work. Its come up with about 30 errors mostly saying ; is expected when there is one there, no storage class or type specifier, and declaration expected, not sure what these mean. I have looked at two turtorials and they both look extremely similar and mine looks the same, so not sure what these missing things are.
Heres my code
#include <windows.h>
LRESULT CALLBACK WindowFunc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
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 hThisInst,
HINSTANCE hPrevInst,
LPSTR lpszArgs,
int nWinMode);
{
WNDCLASS wcls;
HWND hwnd;
MSG msg;
LPCWSTR szClassName = L"ThreadsProgram";
LPCWSTR szWinName = L"My Threads Program"
//Register Class
wcls.style =0;
wcls.lpfnWndProc =WindowFunc;
wcls.cbClsExtra =0;
wcls.cbWndExtra =0;
wcls.hInstance =hThisInst;
wcls.hIcon =LoadIcon(NULL, IDI_APPLICATION);
wcls.hCursor =LoadCurser(NULL, IDC_ARROW);
wcls.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
wcls.lpszMenuName =NULL;
wcls.lpszClassName =szClassName;
if(!RegisterClass(&wcls))
{
MessageBox(NULL, "Window Registration Failed!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
//Make Window
hwnd = CreateWindow(szClassName,
szWinName,
WS_OVERLAPPINGWINDOW,
100,
100,
400,
400,
HWND_DESKTOP,
NULL,
hThisInst,
NULL);
//Show Window
if(hwnd == NULL)
{
MessageBox(NULL, "Window Failed!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nWinMode);
UpdateWindow(hwnd);
//Main Message Loop
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
The first problem I see is here:
int WINAPI WinMain(HINSTANCE hThisInst,
HINSTANCE hPrevInst,
LPSTR lpszArgs,
int nWinMode); /* <---- This semi-colon causes grief! */
{
WNDCLASS wcls;
You have a declaration of a function because of the semicolon after int nWinMode);.
Remove it.
There may also be other problems; I didn't look further and don't plan to do so. The compiler will guide you if your own code review won't help.
A lot of typos there.
semicolon after the WinMain
MessageBox() function taking 3 instead of 4 params.
LPWCSTR params
ShowWindow() with nCmdShow doesn't ... show
WS_OVERPLAPPEDWINDOW (not WS_OVERLAPPINGWINDOW)
LoadCursor instread of LoadCurser
Should work now. Next time type carefully
#include <windows.h>
LRESULT CALLBACK WindowFunc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
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 hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode)
{
WNDCLASS wcls;
HWND hwnd;
MSG msg;
LPCSTR szClassName = "ThreadsProgram";
LPCSTR szWinName = "My Threads Program";
//Register Class
wcls.style =0;
wcls.lpfnWndProc =WindowFunc;
wcls.cbClsExtra =0;
wcls.cbWndExtra =0;
wcls.hInstance =hThisInst;
wcls.hIcon =LoadIcon(NULL, IDI_APPLICATION);
wcls.hCursor =LoadCursor(NULL, IDC_ARROW);
wcls.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
wcls.lpszMenuName =NULL;
wcls.lpszClassName =szClassName;
if(!RegisterClassA(&wcls))
{
MessageBoxA(NULL, 0, "Window Registration Failed!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
//Make Window
hwnd = CreateWindowA(szClassName, szWinName,
WS_OVERLAPPEDWINDOW,
100, 100, 400, 400,
HWND_DESKTOP,
NULL, hThisInst, NULL);
//Show Window
if(hwnd == NULL)
{
MessageBoxA(NULL, 0, "Window Failed!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, SW_SHOW/*nWinMode*/);
UpdateWindow(hwnd);
//Main Message Loop
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}