#include <stdio.h>
#include <stdlib.h>
#define WINVER 0x0500
#include <windows.h>
/// Glabal Handle
HANDLE StdHandle;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
StdHandle = GetStdHandle(STD_OUTPUT_HANDLE); // Console window
MSG Msg ;
while (GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
if(wParam == VK_LCONTROL)
printf ("LSHIFT");
break;
return 0 ;
}
return DefWindowProc(hWnd, msg, wParam, lParam) ;
}
This code can be compiled with mingw32-GCC without any warnings and errors.
It should print out "LSHIFT" if the left control is pressed, but it didn't.
Why?
Your program doesn't create a window, so it can't receive any window messages.
You'll typically want to create and register a window class (using RegisterClass() or RegisterClassEx()), then create an instance of the window using CreateWindow() or CreateWindowEx().
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);
}
}
First: I'm using Visual Studio 2010 on Windows XP - 32 Bit.
Right now I'm trying to write a DLL which will enable another application to work with low level keyboard hooks.
Even though I got it to work - I now want to understand why.
The non-working code:
#include <Windows.h>
#include <stdio.h>
static HINSTANCE hinst;
static HHOOK kbdHook = NULL;
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
printf(":"); fflush(stdout);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
hinst = hinstDLL;
CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
kbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hinst, 0);
break;
case DLL_PROCESS_DETACH:
UnhookWindowsHookEx(kbdHook);
break;
default:
break;
}
return TRUE;
}
The working code:
#include <Windows.h>
#include <stdio.h>
static HINSTANCE hinst;
static HHOOK kbdHook = NULL;
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
printf(":"); fflush(stdout);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
MSG msg;
kbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
hinst = hinstDLL;
CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
break;
case DLL_PROCESS_DETACH:
UnhookWindowsHookEx(kbdHook);
break;
default:
break;
}
return TRUE;
}
The only difference is that I moved the SetWindowsHookEx-call from DllMain to ThreadProc.
The question: Why does this make all the difference?
This is all explained in the documentation for LowLevelKeyboardProc callback function:
This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.
Your non-working code installs the hook on a thread, that doesn't run a message loop.
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;
}
Is it absolutely necessary to always build and register a new WNDCLASS(EX) for your application? And then use the lpszClassName for the main window?
Isn't there some prebuilt class name we can use for a main window, like there is "Button" and "Edit" for buttons and text-boxes etc.?
You can create a mini app out of a dialog resource, you use CreateDialog() instead of CreateWindow(). Boilerplate code could look like this, minus the required error checking:
#include "stdafx.h"
#include "resource.h"
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
DestroyWindow(hDlg);
PostQuitMessage(LOWORD(wParam)-1);
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
HWND hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
if (hWnd == NULL) DebugBreak();
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
Which assumes you created a dialog with the resource editor using id IDD_DIALOG1.
There are no pre-defined window classes for top-level application windows. You must register a window class for your application, or use a dialog.
I'm trying to write a callback for my timer. I defined the TimerProc like this:
void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
//body of callback
}
and then the SetTimer defined like this:
myTimer = SetTimer(NULL,Timer_ID,30000,TimerProc);
my problem is that the callback never being called once the time elpassed (30 sec).
thank's for help.
SetTimer works by sending a WM_TIMER message to the default window procedure. Hence, as the MSDN states:
When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.
So make sure that you have a Message Loop running.
Quick test code. Works fine for me.
#include <windows.h>
static const TCHAR gc_szClassName[] = TEXT("Test");
static const TCHAR gc_szWindowTitle[] = TEXT("Test");
#define IDT_TIMER 0x100
VOID CALLBACK TimerProc(HWND hWnd, UINT uMessage, UINT_PTR uEventId, DWORD dwTime)
{
// display a message box to see the results of our beautiful program
MessageBox(hWnd, TEXT("This should pop up every 10 seconds.."), TEXT("Yay!"), MB_OK | MB_ICONINFORMATION);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
switch (uMessage)
{
case WM_CREATE:
// run every 10 seconds
SetTimer(hWnd, IDT_TIMER, 10000, TimerPRoc);
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
KillTimer(hWnd, IDT_TIMER);
PostQuitMessage(EXIT_SUCCESS);
break;
}
return DefWindowProc(hWnd, uMessage, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCommandLine, int nShowCommand)
{
// define variables
HWND hWnd;
WNDCLASS wc;
MSG msg;
// unused parameters
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpszCommandLine);
UNREFERENCED_PARAMETER(nShowCommand);
// initialize WNDCLASS structure
ZeroMemory(&wc, sizeof(wc));
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = gc_szClassName;
// attempt to register the class
if (RegisterClass(&wc) != 0)
{
// attempt to create the window
hWnd = CreateWindow(gc_szClassName, gc_szWindowTitle, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
if (hWnd != NULL)
{
// retrieve messages
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// use the return-code from the window
return (int)msg.wParam;
}
}
return EXIT_FAILURE;
}