SetWindowshookEx sometimes not working after dll injection - c++

I am using this lib http://code.google.com/p/injex/ to inject a dll that contains a keyboard hook function. The dll is simple, just create a thread and use the 'setWindowsHookEx' function.
The injection was always successful, but the keyboard hook didn't work for all the cases.
I wrote a simple 'hello world' win32 app, and use injex.exe to inject the keyboard hook dll into it. All works as expected.
If I choose a complex program to inject (A game written in delphi), the dll was successfully injected(I can see the injected main form), but it failed to hook the keyboard.
So my question is:
Is the failure of keyboard hook because of the injection method, or the keyboard hook function?
Is it possible that a dll can be injected, but its functionalities are not guaranteed?
So any advices are welcome.
Here is the dll code:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
//GUI==============================================================================
#define MYMENU_EXIT (WM_APP + 101)
#define MYMENU_MESSAGEBOX (WM_APP + 102)
HINSTANCE inj_hModule; //Injected Modules Handle
HWND prnt_hWnd; //Parent Window Handle
//WndProc for the new window
LRESULT CALLBACK DLLWindowProc (HWND, UINT, WPARAM, LPARAM);
//Register our windows Class
BOOL RegisterDLLWindowClass(wchar_t szClassName[])
{
WNDCLASSEX wc;
wc.hInstance = inj_hModule;
wc.lpszClassName = (LPCWSTR)L"InjectedDLLWindowClass";
wc.lpszClassName = (LPCWSTR)szClassName;
wc.lpfnWndProc = DLLWindowProc;
wc.style = CS_DBLCLKS;
wc.cbSize = sizeof (WNDCLASSEX);
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
if (!RegisterClassEx (&wc))
return 0;
}
//Creating our windows Menu
HMENU CreateDLLWindowMenu()
{
HMENU hMenu;
hMenu = CreateMenu();
HMENU hMenuPopup;
if(hMenu==NULL)
return FALSE;
hMenuPopup = CreatePopupMenu();
AppendMenu (hMenuPopup, MF_STRING, MYMENU_EXIT, TEXT("Exit"));
AppendMenu (hMenu, MF_POPUP, (UINT_PTR) hMenuPopup, TEXT("File"));
hMenuPopup = CreatePopupMenu();
AppendMenu (hMenuPopup, MF_STRING,MYMENU_MESSAGEBOX, TEXT("MessageBox"));
AppendMenu (hMenu, MF_POPUP, (UINT_PTR) hMenuPopup, TEXT("Test"));
return hMenu;
}
//Our new windows proc
LRESULT CALLBACK DLLWindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_KEYDOWN:
if(wParam == VK_HOME) {
//TextOut(hdc,15, 15, keydown, _tcslen(keydown));
// etc.
MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL);
}
break;
case WM_COMMAND:
switch(wParam)
{
case MYMENU_EXIT:
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;
case MYMENU_MESSAGEBOX:
MessageBox(hwnd, L"Test", L"MessageBox",MB_OK);
break;
}
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
//HOOK LIB=====================================================================================================
// This will be called when keys are pressed.
HHOOK g_kbHook=NULL;
LRESULT CALLBACK KeyboardHook(int nCode,WPARAM wParam,LPARAM lParam)
{
KBDLLHOOKSTRUCT* key;
if(wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN){
key = (KBDLLHOOKSTRUCT*)lParam;
if(key->vkCode == VkKeyScan('a')){
//odprintf("You pressed 'a'");
MessageBox(NULL, _T("Pressed a"), _T("Win32 Guided Tour"), NULL);
}
if(key->vkCode == VK_F1){
MessageBox(NULL, _T("Pressed F1"), _T("Win32 Guided Tour"), NULL);
//odprintf("You pressed F1");
}
}
return 0;
}
LRESULT CALLBACK _KeyboardHookProc(int nCode,WPARAM wParam,LPARAM lParam){
//g_kbHookFunction(nCode,wParam,lParam);
KeyboardHook(nCode,wParam,lParam);
return CallNextHookEx(g_kbHook,nCode,wParam,lParam);
};
//ENTRY POINT================================================================================================
//our start function, start everything here
DWORD WINAPI start(LPVOID lpParam){
// START YOUR CODE HERE...
// Lay some hooks, season libraly with pwnsauce.
// Do whatever you want here, this is your thread to play with.
// NOTE: This is used as the starting function in most examples.
// STOP HERE.
MSG messages;
wchar_t *pString = reinterpret_cast<wchar_t * > (lpParam);
HMENU hMenu = CreateDLLWindowMenu();
RegisterDLLWindowClass(L"InjectedDLLWindowClass");
prnt_hWnd = FindWindow(L"Window Injected Into ClassName", L"Window Injected Into Caption");
HWND hwnd = CreateWindowEx (0, L"InjectedDLLWindowClass", L"mywindow", WS_EX_PALETTEWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, prnt_hWnd, hMenu,inj_hModule, NULL );
ShowWindow (hwnd, SW_SHOWNORMAL);
g_kbHook = SetWindowsHookEx(WH_KEYBOARD_LL,_KeyboardHookProc,GetModuleHandle(NULL),0);
if (!g_kbHook) {
}
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return 1;
g_kbHook = NULL;
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
// We create a new thread to do our bidding in, this way we don't hold the loader lock.
// We close the handle to the thread for various reasons.
inj_hModule = hModule;
CloseHandle(CreateThread(NULL, 0, start, (LPVOID)hModule, 0, NULL));
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

If the process you're trying to hook already installed its own keyboard hook, that hook may not be calling CallNextHookEx() to pass the message along to your hook. See the description at MSDN (note the explanation in the Return Value section). If that is indeed the cause of your problem, your only option may be to install your hook before the process installs its own hook.

Related

Getting key code from pressing keyboards special keys (ex. macro keys on Razer Blackwidow Chroma)

I am new to c++ and developing windows desktop application.
I want to catch the event when user presses a non-standard key on keyboard, ex. macro key on Razer Blackwidow Chroma.
Currently I'm successfully catching all the other standard keys:
WM_KEYDOWN: 0x41
WM_CHAR: a
INPUT HAPPENED, I want this triggered when pressing macro keys!
WM_KEYUP: 0x41
.. but pressing M1-M5 on this keyboard does not trigger the event.
I also added the keyboard to be listened as RAWINPUTDEVICE, but still nothing.
Code fragment from message WndProc:
..
switch (message)
{
case WM_CREATE:
OutputDebugStringW(L"Hello World initialization...\n");
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = 0x06;
Rid[0].dwFlags = 0;
Rid[0].hwndTarget = 0;
if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
//registration failed. Call GetLastError for the cause of the error
OutputDebugStringW(L"Error");
}
break;
case WM_KEYDOWN:
swprintf_s(msg, L"WM_KEYDOWN: 0x%x\n", wParam);
OutputDebugString(msg);
break;
case WM_KEYUP:
swprintf_s(msg, L"WM_KEYUP: 0x%x\n", wParam);
OutputDebugString(msg);
break;
case WM_CHAR:
swprintf_s(msg, L"WM_CHAR: %c\n", (wchar_t)wParam);
OutputDebugString(msg);
break;
case WM_INPUT:
OutputDebugStringW(L"INPUT HAPPENED, I want this triggered when pressing macro keys! \n");
break;
..
Do I need to look at keyboard not as a RAWINPUTDEVICE, but as a USB device, can I get the signal then?
Or am I wrong in assuming that keyboard, by default, is sending a key code signal to OS regardless of driver presence on the OS?
If you wanna play around and test this on your keyboard, here's the whole file:
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
// Global variables
// The main window class name.
static TCHAR szWindowClass[] = _T("DesktopApp");
// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("Windows Desktop Hello World Application");
HINSTANCE hInst;
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// Store instance handle in our global variable
hInst = hInstance;
// The parameters to CreateWindow explained:
// szWindowClass: the name of the application
// szTitle: the text that appears in the title bar
// WS_OVERLAPPEDWINDOW: the type of window to create
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
// 500, 100: initial size (width, length)
// NULL: the parent of this window
// NULL: this application does not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 100,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShow);
UpdateWindow(hWnd);
// Main message loop:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, Windows desktop!");
wchar_t msg[255];
switch (message)
{
case WM_CREATE:
OutputDebugStringW(L"Hello World initialization...\n");
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = 0x06;
Rid[0].dwFlags = 0;
Rid[0].hwndTarget = 0;
if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
//registration failed. Call GetLastError for the cause of the error
OutputDebugStringW(L"Error");
}
break;
case WM_KEYDOWN:
swprintf_s(msg, L"WM_KEYDOWN: 0x%x\n", wParam);
OutputDebugString(msg);
break;
case WM_KEYUP:
swprintf_s(msg, L"WM_KEYUP: 0x%x\n", wParam);
OutputDebugString(msg);
break;
case WM_CHAR:
swprintf_s(msg, L"WM_CHAR: %c\n", (wchar_t)wParam);
OutputDebugString(msg);
break;
case WM_INPUT:
OutputDebugStringW(L"INPUT HAPPENED, I want this triggered when pressing macro keys! \n");
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,5, 5,greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}

Dll process hook is not working

I want to hook my KeyboardProc from dll into my created window using dll injection. I want to see message boxes when pressing keys with focused injected window, but my code is not working properly.
Injected window code:
#include <windows.h>
#include <iostream>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (lParam)
{
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgs, int nCmdShow)
{
HWND hwnd;
LPCTSTR className = L"WNDCLASS";
LPCTSTR windowName = L"Window";
WNDCLASSEX wcex;
memset(&wcex, 0, sizeof(wcex));
wcex.cbSize = sizeof(wcex);
wcex.hInstance = hInstance;
wcex.lpszClassName = className;
wcex.style = CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
if (!RegisterClassEx(&wcex))
{
return -1;
}
hwnd = CreateWindowEx(NULL, className, windowName, WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, hInstance, NULL);
if (!hwnd)
{
return -2;
}
MSG msg;
ShowWindow(hwnd, SW_NORMAL);
UpdateWindow(hwnd);
while (GetMessage(&msg, hwnd, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return
msg.lParam;
}
dll code:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <tchar.h>
HHOOK hhkKb;
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (wParam == WM_KEYDOWN)
{
MessageBox(0, L"DOWN", L"keyboard key down in dll", MB_ICONINFORMATION);
}
else if (wParam == WM_KEYUP)
{
MessageBox(0, L"UP", L"keyboard key up in dll", MB_ICONINFORMATION);
}
return
CallNextHookEx(hhkKb, nCode, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
HWND windowHandle = FindWindow(NULL, L"Window");
if (windowHandle == NULL)
{
MessageBox(NULL, L"Error", L"Handle is null", MB_ICONERROR);
return TRUE;
}
DWORD threadId = GetWindowThreadProcessId(windowHandle, NULL);
hhkKb = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hModule, threadId);
MessageBox(NULL, L"Success", L"Sucessfully injected dll", MB_ICONINFORMATION); //shows that message
break;
}
case DLL_PROCESS_DETACH:
{
UnhookWindowsHookEx(hhkKb);
break;
}
}
return TRUE;
}
I see "Sucessfully injected dll" message, but when I'm pressing keys into injected window, the KeyboardProc is not called, what I'm doing wrong?
using dll injection
unclear how you do this dll injection, but based on your previous question can assume that you manually inject your dll by CreateRemoteThread to LoadLibraryA. and in any case call SetWindowsHookEx from dll entry point is error by sense.
formally if thread, which call SetWindowsHookEx, exit - hooks will be automatically removed. so can say that on exit thread indirect call UnhookWindowsHookEx. don't sure are this clear documented, but can be view in next simply test
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
DbgPrint("%x>KeyboardProc(%x)\n", GetCurrentThreadId(), wParam);
return CallNextHookEx(0, nCode, wParam, lParam);
}
ULONG HookThread(PVOID threadId)
{
DbgPrint("%x>HookThread(%x)\n", GetCurrentThreadId(), (ULONG)(ULONG_PTR)threadId);
if (HHOOK hhk = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, (HINSTANCE)&__ImageBase, (ULONG)(ULONG_PTR)threadId))
{
Sleep(10000);//10 sec
//MessageBoxW(0,0,L"Close Me", MB_ICONWARNING);
}
return 0;
}
void test()
{
if (HANDLE hThread = CreateThread(0, 0, HookThread, (PVOID)(ULONG_PTR)GetCurrentThreadId(), 0,0))
{
CloseHandle(hThread);
MessageBoxW(0,0,L"Press Buttons here", MB_ICONINFORMATION);
}
}
first several seconds (or until you close MessageBoxW L"Close Me" if chose this variant) you can view dbgprint from KeyboardProc when you press buttons on first messagebox. after HookThread exit - no more KeyboardProc will be called.
so if you inject dll via CreateRemoteThread - this thread call LoadLibrary, then SetWindowsHookEx will be called in this thread, and finally thread just exit - and this remove effect of call SetWindowsHookEx - hook will be remove.
however if we use SetWindowsHookEx we not need manually inject dll to process. visa versa - this api special design for automatically inject dll to remote process. and of course you must not call SetWindowsHookEx from dll entry point - this is nonsense. you need call SetWindowsHookEx from remote process - as result your dll and will be injected to target process. reread Installing and Releasing Hook Procedures

C++ event handling for click on notification area Icon Windows

I want to achieve some kind of event handling for Windows. I have a program, that has a symbol in the Notification Area (System Tray) and I want the programm to show up again, when the user clicks on the Icon. Is there a simple Way to implement that in c++ as an Event? I have only found ways to this in C#.
It is a console Application and I want to change as few things as possible. But there is no WndProc handler for Console Application as far as I can tell.
Why no WndProc? Console application is a perfect win32 application, and it can use anything which non-console application can use.
Here's a simple, but a bit long example.
#include <windows.h>
#include <shellapi.h>
#include <iostream>
#include <cstring>
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
BOOL WINAPI ConsoleRoutine(DWORD dwCtrlType);
LPCWSTR lpszClass = L"__hidden__";
int main()
{
HINSTANCE hInstance = GetModuleHandle(nullptr);
WNDCLASS wc;
HWND hWnd;
MSG msg;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = nullptr;
wc.hCursor = nullptr;
wc.hIcon = nullptr;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = lpszClass;
wc.lpszMenuName = nullptr;
wc.style = 0;
RegisterClass(&wc);
hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, hInstance, nullptr);
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static NOTIFYICONDATA nid;
switch (iMsg)
{
case WM_CREATE:
std::memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.hWnd = hWnd;
nid.uID = 0;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_APP + 1;
nid.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
lstrcpy(nid.szTip, L"con-notify");
Shell_NotifyIcon(NIM_ADD, &nid);
Shell_NotifyIcon(NIM_SETVERSION, &nid);
return 0;
case WM_APP + 1:
switch (lParam)
{
case WM_LBUTTONDBLCLK:
std::cout << "notify dblclk" << std::endl;
break;
case WM_RBUTTONDOWN:
case WM_CONTEXTMENU:
break;
}
break;
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &nid);
MessageBox(nullptr, L"asdf", L"asdf", MB_OK);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,iMsg,wParam,lParam);
}
You probably want not to mess up your console program with message loop. If so, you can put notification code into another thread.

WinApi task killing

I have super simple WinApi program. Close button does not destroy process of the program. What should be added?
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hINSTANCE;
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpstr,
int nCmdShow) {
// VARIABLES
TCHAR className[] = _T("win32api");
TCHAR windowName[] = _T("Protected Window");
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_INFORMATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = className;
wcex.hIconSm = LoadIcon(NULL, IDI_SHIELD);
if (!RegisterClassEx(&wcex)) {
MessageBox(NULL, _T("Cannot register window"), _T("Error"), MB_OK | MB_ICONERROR);
return 0;
}
HWND hWnd = CreateWindow(className,
windowName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
300,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd) {
MessageBox(hWnd, _T("Call to register windows isn't working"), _T("Error"), NULL);
return 1;
}
hINSTANCE = hInstance;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, hWnd, 0, 0) != 0 || GetMessage(&msg, hWnd, 0, 0) != -1) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.lParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uInt, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
switch (uInt) {
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 10, 20, _T("Text sample right here boyz."), _tcsclen(_T("Text sample right here boyz.")));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uInt, wParam, lParam);
break;
}
return 0;
}
If I add one more case
case WM_CLOSE:
PostQuitMessage(0);
break;
It doesnt close at all (pressing close button is not doing anything). Any other tips are very appreciated.
Your message loop is wrong, for two reasons:
you are calling GetMessage() twice. Don't do that! Think of what happens if you do. If the GetMessage() call on the left-hand side of || were to detect WM_QUIT (which it can't, see further below), it would return 0. Which would cause || to call the GetMessage() on the right-hand side, ignoring the WM_QUIT from the previous call and blocking the loop until a new message arrives later. You should call GetMessage() only once per loop iteration, and then act on the return value as needed:
BOOL bRet;
do
{
bRet = GetMessage(&msg, hWnd, 0, 0);
if (bRet == 0) break;
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
while (1);
However, you are also filtering messages by HWND (don't do that!), and so it will only return messages that are posted to the specified HWND via PostMessage(). PostQuitMessage() posts its WM_QUIT message to the input queue of the calling thread itself, not to the HWND. So the filtering will never see the WM_QUIT message. In order for WM_QUIT to break the loop, you need to stop filtering by HWND altogether, or at least make an unfiltered call periodically.
Your message loop should look like this instead. This is the standard message loop:
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Note in this case, there is no need to handle -1 from GetMessage()!.
To close the app, you need to destroy the window. Typically that's done in one of two ways:
Have your WM_CLOSE handler call DestroyWindow.
Have the DefWindowProc handle the message after you do your thing.
Your WndProc is a little out of the ordinary. I usually see them written as:
{
switch(msg)
{
case WM_CLOSE:
// prompt user, clean stuff up, etc.
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
// Other cases here. Most will fall out of the switch so that
// DefWindowProc can handle them (for other system notifications).
// Only return from the case if you really don't want anybody else
// to handle the message.
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
For specifics on WM_CLOSE, see https://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspx, which specifically says that you must call DestroyWindow or let DefWindowProc do it.

C++ Win32 not retrieving edit data even though edit is in scope

I am a little new to C++, so I am starting out with a text editor program. I am developing this project in NetBeans IDE. Currently the application is all in the main source file. When I compile and run the project, I get no errors and the project proceeds to function.
However, I have some sort of error or bug that lies within the application as it is running. This bug is associated with the Edit Control and the GetWindowText() method. The problem is located in the saveFile() function. What I am making of the GetWindowText() function is to test to see if I can retrieve text from the Edit Control and use it for my needs. I tried to emulate it through a simple MessageBox() function, and I got nothing.
Source code [FULL]:
/*
* File: main.cpp
* Author: CA1K
*
* Created on November 1, 2015, 9:58 PM
*/
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <string>
using namespace std;
// [ PROGRAM PROCEDURES ]
//=========================================================
/*Really what these are used for is to address conditions to
*the WS_COMMAND case, these are registered as integers
*/
#define IDC_MAIN_EDIT 0//edit ID
#define EXIT_PROC 1//the exit procedure
#define ABOUT_PROC 2//the trigger for the "about" window
#define CLONE_PROC 3//spawn a new window
#define SAVE_PROC 4//save procedure
#define OPEN_PROC 5//copy procedure
//=========================================================
// [ DEVELOPER FRIENDLY VARIABLES ]
//=========================================================
const char g_szClassName[] = "CPadx1"; //window class name
const char g_Title[] = "CPad"; //window title
const char g_About[] = "CPad is a program developed by CA1K. It is entirely made from the win32 API. For more programs, go to ca1k.xkotto.com.";
int dim = 600;//window dimensions(square)
TCHAR buffer[512];
//=========================================================
// [ OBJECT BUILDING ]
//=========================================================
void makeMenu(HWND hwnd){
HMENU hMenubar;
HMENU hMenu;
HMENU hMenu2;
hMenubar = CreateMenu();
hMenu = CreateMenu();
hMenu2 = CreateMenu();
AppendMenuW(hMenu, MF_STRING, SAVE_PROC, L"&Save/Save as");
AppendMenuW(hMenu, MF_STRING, OPEN_PROC, L"&Open file");
AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenuW(hMenu, MF_STRING, CLONE_PROC, L"&New Window");
AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenuW(hMenu, MF_STRING, ABOUT_PROC, L"&About");
AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&File");
AppendMenuW(hMenu2, MF_STRING, EXIT_PROC, L"&Exit");
AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu2, L"&Config");
SetMenu(hwnd, hMenubar);
}
void dispWnd(HWND hwnd){//this function spawns a new window
HINSTANCE hInstance;
HWND newChild = CreateWindowEx(0, g_szClassName, g_Title, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, dim, dim, hwnd, NULL, hInstance, NULL);
HWND GetParent(HWND hwnd);
ShowWindow(newChild, 1);
UpdateWindow(newChild);
}
void makeEdit(HWND hwnd, HWND hEdit){//this function creates the edit
HINSTANCE hInstance;
RECT rect;
int pwidth;
int pheight;
if(GetWindowRect(hwnd, &rect))
{
pwidth = rect.right - rect.left;
pheight = rect.bottom - rect.top;
}
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT","",
WS_CHILD|WS_VISIBLE|ES_AUTOVSCROLL|ES_AUTOHSCROLL|ES_MULTILINE,
0,0,pwidth,pheight,hwnd,(HMENU)IDC_MAIN_EDIT,
hInstance,NULL);
}
void saveFile(HWND hEdit){
GetWindowText(hEdit, buffer, 512);
MessageBox(NULL, buffer, "Test", MB_ICONINFORMATION);
}
//=========================================================
// [ SOFTWARE PROCESSING ]
//=========================================================
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND winEdit;
switch(msg)
{
/*WINDOW ACTIONS*/
case WM_CREATE:{//on window creation
makeMenu(hwnd);
makeEdit(hwnd,winEdit);
}
break;
case WM_SIZE:
makeEdit(hwnd,winEdit);
break;
case WM_COMMAND://window actions
switch(LOWORD(wParam))
{
case ABOUT_PROC:
MessageBox(NULL, g_About, "About", MB_ICONINFORMATION);
break;
case EXIT_PROC:
PostQuitMessage(0);//exit program
break;
case CLONE_PROC:
dispWnd(hwnd);
break;
case SAVE_PROC:
saveFile(winEdit);
break;
}
break;
case WM_CLOSE://on window close
DestroyWindow(hwnd);
break;
case WM_DESTROY://on window destroy
PostQuitMessage(0);
break;
default://default method
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 = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
g_Title,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, dim, dim,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
//=========================================================
I am questioning whether I have the scopes wrong, or something else. Feed back would be much appreciated.
-CA1K
You need to make winEdit a static variable. This is because you use it in more than one message, like WM_CREATE and WM_COMMAND. Then, you need to pass a pointer to an HWND to your makeEdit function:
makeEdit(hwnd, &winEdit);
So your overall window procedure should look like this:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND winEdit;
switch(msg)
{
/*WINDOW ACTIONS*/
case WM_CREATE:{//on window creation
makeMenu(hwnd);
makeEdit(hwnd, &winEdit);
}
break;
case WM_SIZE:
makeEdit(hwnd,winEdit);
break;
case WM_COMMAND://window actions
switch(LOWORD(wParam))
{
case ABOUT_PROC:
MessageBox(NULL, g_About, "About", MB_ICONINFORMATION);
break;
case EXIT_PROC:
PostQuitMessage(0);//exit program
break;
case CLONE_PROC:
dispWnd(hwnd);
break;
case SAVE_PROC:
saveFile(winEdit);
break;
}
break;
case WM_CLOSE://on window close
DestroyWindow(hwnd);
break;
case WM_DESTROY://on window destroy
PostQuitMessage(0);
break;
default://default method
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}