I'm trying to learn how to create a message-only window inside of a dll, but the process being injected by this dll 'hangs'/never exits when I close it.
I get the message box DLL_PROCESS_DETACH, but it remains open in the task manager.
It only happens when I call the function Main(), I'm probably doing something wrong.
Source code of the dll:
// Global variables.
HWND processhWnd = nullptr;
bool disableHooks = false;
class std::future<void> wndproc_thread;
class std::future<void> wm_copydata_thread;
LRESULT(WINAPI* DefWindowProcW_Hook)(HWND, UINT, WPARAM, LPARAM) = DefWindowProcW;
LRESULT WINAPI HookedDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (disableHooks)
return DefWindowProcW_Hook(hWnd, Msg, wParam, lParam);
switch (Msg)
{
}
return DefWindowProcW_Hook(hWnd, Msg, wParam, lParam);
}
#pragma region getprocessHWND
struct handle_data {
unsigned long process_id;
HWND window_handle;
};
BOOL Is_Main_Window(HWND handle)
{
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}
BOOL CALLBACK Enum_Windows_Callback(HWND handle, LPARAM lParam)
{
//static wchar_t title[200]; how to print the window title?
//GetWindowText(handle, title, 200);
//doPrint("title: ", title);
handle_data& data = *(handle_data*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (data.process_id != process_id || !Is_Main_Window(handle))
return TRUE;
data.window_handle = handle;
return FALSE;
}
HWND Find_Main_Window(unsigned long process_id)
{
handle_data data;
data.process_id = process_id;
data.window_handle = 0;
EnumWindows(Enum_Windows_Callback, (LPARAM)&data);
return data.window_handle;
}
#pragma endregion
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
Sleep(1000);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)DefWindowProcW_Hook, HookedDefWindowProcW);
LONG lError = DetourTransactionCommit();
if (lError != NO_ERROR) {
MessageBox(HWND_DESKTOP, L"Failed to detour", L"", MB_OK);
return FALSE;
}
wndproc_thread = std::async(std::launch::async, []
{ Main(); });
}
break;
case DLL_PROCESS_DETACH:
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)True_WriteFile, HookedWriteFile);
LONG lError = DetourTransactionCommit();
if (lError != NO_ERROR) {
MessageBox(HWND_DESKTOP, L"DLL_PROCESS_DETACH", L"", MB_OK);
return FALSE;
}
}
break;
}
return TRUE;
}
void WM_COPYDATA(std::wstring data)
{
}
// Step 4: the Window Procedure.
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COPYDATA:
{
PCOPYDATASTRUCT pcds = reinterpret_cast<PCOPYDATASTRUCT>(lParam);
std::wstring received_data = (wchar_t*)pcds->lpData;
std::wstring data = received_data;
wm_copydata_thread = std::async(std::launch::async, [data]
{ WM_COPYDATA(data); });
doPrint("WM_COPYDATA: ", data);
return 1;
}
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
case WM_QUIT:
//OutputDebugString(L"WM_QUIT");
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
// Step 1-3 Creating a window procedure.
int Main()
{
WNDCLASSEX wc{};
HWND hWnd = nullptr;
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 = 0;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
DWORD PID = GetCurrentProcessId();
HWND processhWnd = Find_Main_Window(PID);
// The class name of the message-only window will be the
// window title of the process being injected.
std::wostringstream ss;
ss << std::hex << processhWnd;
std::wstring ClassName = ss.str();
wc.lpszClassName = ClassName.c_str();
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
DWORD err = GetLastError();
std::wstring error = L"Window Registration Failed.\nError: " + std::to_wstring(int(err));
MessageBox(NULL, error.c_str(), L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
// Message-only window (HWND_MESSAGE).
// https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#message-only-windows
hWnd = CreateWindowEx(
WS_EX_TOOLWINDOW,
ClassName.c_str(), // name of the class, as passed to the RegisterClass function
NULL,
NULL,
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, // X,Y,W,H
HWND_MESSAGE,
NULL, 0, NULL);
if (hWnd == NULL)
{
std::wstring error = L"Window creation failed.\nError: " + std::to_wstring(int(err));
MessageBox(NULL, error.c_str(), L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
doPrint("\nprocesshWnd: ", processhWnd);
doPrint("HWND_MESSAGE: ", hWnd, "\n");
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
// Step 3: The Message Loop
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return 0; // Msg.wParam;
}
The way I'm creating/calling the WndProcedure using threads, etc, is it 'correctly'?
My goal is to send data to the dll using WM_COPYDATA.
Related
I have been trying to create a Window whose title bar could be in any language. But I am getting something like ▯*. I writing as escape characters as of now. I am attesting the entirity of the code.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string>
LRESULT CALLBACK WindowProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) {
switch(Message) {
case WM_KEYDOWN: {
switch(WParam) {
case 'O': {
DestroyWindow(Window);
} break;
}
} break;
case WM_DESTROY: {
PostQuitMessage(0);
} break;
default: {
return DefWindowProc(Window, Message, WParam, LParam);
}
}
return 0;
}
int WINAPI WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, PSTR CmdLine, int CmdShow) {
WNDCLASSW WindowClass = {0};
const wchar_t* ClassName = L"MyWindowClass";
WindowClass.lpfnWndProc = WindowProc;
WindowClass.hInstance = Instance;
WindowClass.lpszClassName = ClassName;
WindowClass.hCursor = LoadCursor(NULL, IDC_CROSS);
MessageBoxW(0, L"\u0906\u092a", L"\u0906\u092a", 0);
if(!RegisterClassW(&WindowClass)) {
MessageBoxW(0, L"RegisterClass failed", 0, 0);
return GetLastError();
}
HWND Window = CreateWindowExW(0, ClassName, L"\u0906\u092a",
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
0, 0, Instance, 0);
if(!Window) {
MessageBoxW(0, L"CreateWindowEx failed", 0, 0);
return GetLastError();
}
int Running = 1;
while(Running) {
MSG Message;
while(GetMessageW(&Message, NULL, 0, 0)) {
if(Message.message == WM_QUIT) Running = 0;
TranslateMessage(&Message);
DispatchMessage(&Message);
}
}
return 0;
}
I was expecting the title bar to be something like 'आप'
int Num = 0;
LRESULT CALLBACK TestWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
RECT rc;
GetClientRect(hWnd, &rc);
RECT Winrc;
GetWindowRect(hWnd, &Winrc);
SYSTEMTIME time;
GetLocalTime(&time);
static const wchar_t* BoxTxt = L"";
static int MeIs = Num;
switch (message)
{
case WM_CREATE:
{
SetWindowLong(hWnd, GWL_EXSTYLE,
GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), 220, LWA_ALPHA);
//GhWnd = hWnd;
break;
}
case WM_LBUTTONUP:
{
wchar_t meChar[20] = L"";
_itow(MeIs, meChar, 10);
MessageBox(0, meChar, meChar, 0);
}
case WM_SIZE:
{
InvalidateRect(hWnd, &rc, 1);
break;
}
case WM_NCLBUTTONDBLCLK:
{
break;
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
switch (wmId)
{
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_CLOSE:
{
Num -= 1;
DestroyWindow(hWnd);
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int CreateTestWindow()
{
//Call testwndproc. To reduce the length of the problem description, omit these codes
Num+=1;
return 0;
}
In the above code, when I create multiple windows and click it, it should pop up "1", "2", "3"... But actually all pop up "1".
static int MeIs = 0;
case WM_CREATE:
{
MeIs = Num;
}
Change to the above code and the serial number of the last window will pop up. For example, when the fourth window is created, all windows will pop up "4"
In practical application, each window has its own settings and is stored in the vector. Each window finds its own settings according to its own serial number:
struct Data
{
int x;
int y;
int width;
int height;
const wchar_t* text;
}
std::vector<data>UserData(32);//Max:32
//then read them from file,But the window must know which window it is:UserData[i].
For example,the first window will set their coordinates to UserData[1].x and UserData[1].y,also need to save the file when closing.
Any idea?thank you!
There are a couple of ways to maintain per-window data using the Win32 API.
The simplest is using the GWL_USERDATA slot accessible via GetWindowLongPtr(...) and SetWindowLongPtr(...). A typical way to initialize this user data value is to use the creation parameters passed to the WM_CREATE message by the CreateWindow call.
Code below:
#include <windows.h>
#include <string>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
struct SomeData {
int n;
std::wstring str;
};
int RegisterWindow(HINSTANCE hInstance, const wchar_t* wnd_class) {
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(WHITE_BRUSH);
wc.lpszClassName = wnd_class;
if (!RegisterClass(&wc)) {
return 1;
}
return 0;
}
int CreateWindowWithUserData(HINSTANCE hInstance, const wchar_t* wnd_class, int n, const std::wstring& str) {
auto* data_ptr = new SomeData{ n, str };
if (!CreateWindow(wnd_class, L"Window text", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, data_ptr))
return 2;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
const auto* wnd_class = L"foobar";
RegisterWindow(hInstance, wnd_class);
for (int i = 1; i <= 5; i++) {
CreateWindowWithUserData(hInstance, wnd_class, i, L"blah");
}
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE: {
CREATESTRUCT* create_struct = reinterpret_cast<CREATESTRUCT*>(lParam);
SomeData* user_data = reinterpret_cast<SomeData*>(create_struct->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG>(user_data));
}
return 0;
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_PAINT: {
SomeData* user_data = reinterpret_cast<SomeData*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT r = { 20, 20, 300, 35 };
auto msg = user_data->str + L" " + std::to_wstring(user_data->n);
DrawText(hdc, msg.c_str(), -1, &r, DT_SINGLELINE);
EndPaint(hWnd, &ps);
}
return 0;
case WM_DESTROY: {
SomeData* user_data = reinterpret_cast<SomeData*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
delete user_data;
}
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Another way to do something similar is to use the cbWndExtra extra field when registering the window class, as discussed in this answer.
You can:
Indeed store data in Window. SetProp, SetWindowLong+GWL_USERDATA, SetWindowLong+cbWndExtra
Map HWND to your data, like using c++ std::map
Use a thunk to have an associated object, like ATL, see ATL thunk header for available APIs (have to do it manually for older OSes)
I've successfully set up a mouse hook for a window, and I'd like to detect a drag operation when the left mouse button is clicked. I've tried using DragDetect, as shown below, but it never returns TRUE, and it never suppresses the subsequent mouse-up event (in this code, hwnd is the target window):
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
{
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
switch (wParam)
{
case WM_LBUTTONDOWN:
{
// Get the click point
LPMOUSEHOOKSTRUCT pMouseHookStruct = reinterpret_cast<LPMOUSEHOOKSTRUCT>(lParam);
CPoint ptClick = pMouseHookStruct->pt;
// Drag detect
BOOL fDrag = DragDetect(hwnd, ptClick);
if (fDrag)
{
MessageBox(NULL, L"Drag", NULL, MB_OK);
}
break;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
Does DragDetect not work within hook procedures, or am I just doing something wrong?
As comments pointed, DragDetect does not predict the future. But you can compare the POINT of WM_LBUTTONDOWN and WM_MOUSEMOVE in a click-time.
Sample:
#include <windows.h>
#include <iostream>
using namespace std;
typedef BOOL(*SETHOOK)(HWND hWnd);
typedef BOOL(*UNHOOK)();
LRESULT CALLBACK WndProcFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
int main(int argc, char* argv[])
{
WNDCLASS wc{};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProcFunc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = L"Class_Name";
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
RegisterClass(&wc);
HWND hWnd = CreateWindow(L"Class_Name", L"Test", WS_OVERLAPPEDWINDOW, 0, 0, 1000, 500, NULL, NULL, GetModuleHandle(NULL), NULL);
SETHOOK SetHook;
UNHOOK UnHook;
HMODULE h = LoadLibraryA("PATH\\DLL4.dll");
SetHook = (SETHOOK)GetProcAddress(h, "SetHook");
UnHook = (UNHOOK)GetProcAddress(h, "UnHook");
BOOL i = SetHook(hWnd);
ShowWindow(hWnd, 1);
UpdateWindow(hWnd);
MSG Msg;
while (GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
UnHook();
return 0;
}
DLL:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define PRESS TRUE
#define RELEASE FALSE
HHOOK tHook;
HMODULE hinstDLL;
BOOL button = RELEASE;
BOOL Drag = FALSE;
HWND hWnd;
POINT pt = { 0 };
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode < 0)
{
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LPMOUSEHOOKSTRUCT pMouseHookStruct = reinterpret_cast<LPMOUSEHOOKSTRUCT>(lParam);
if (pMouseHookStruct->hwnd != hWnd)
{
button = RELEASE;
Drag = FALSE;
}
else {
switch (wParam)
{
case WM_LBUTTONDOWN:
{
button = PRESS;
Drag = FALSE;
printf("WM_LBUTTONDOWN\n");
printf("%d , %d\n", pMouseHookStruct->pt.x, pMouseHookStruct->pt.y);
pt.x = pMouseHookStruct->pt.x;
pt.y = pMouseHookStruct->pt.y;
break;
}
case WM_LBUTTONUP:
{
button = RELEASE;
Drag = FALSE;
printf("WM_LBUTTONUP\n");
break;
}
case WM_MOUSEMOVE:
{
if (button == PRESS)
{
printf("%d , %d\n", pMouseHookStruct->pt.x, pMouseHookStruct->pt.y);
if (Drag == FALSE && (abs(pt.x - pMouseHookStruct->pt.x) >= GetSystemMetrics(SM_CXDRAG) || abs(pt.y - pMouseHookStruct->pt.y) >= GetSystemMetrics(SM_CYDRAG)))
{
printf("Drag\n");
Drag = TRUE;
}
}
break;
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
extern "C" __declspec(dllexport) BOOL SetHook(HWND hwnd)
{
hWnd = hwnd;
tHook = SetWindowsHookEx(WH_MOUSE, MouseProc, hinstDLL, 0);
if (tHook == NULL)
return FALSE;
else
return TRUE;
}
extern "C" __declspec(dllexport) BOOL UnHook()
{
return UnhookWindowsHookEx(tHook);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hinstDLL = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I'm trying to make a clipboard queue, allowing me to copy multiple things and then paste them FIFO. To do so, I'm using with Windows API as well as a basic keyboard hook to detect ctrl+c and ctrl+v. My code seems to work however I seem to constantly get a random output from the queue.
#include <Windows.h>
#include <stdio.h>
#include <vector>
using namespace std;
vector<char*> clipboardQueue;
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (wParam == WM_KEYDOWN) {
if (p->vkCode == 0x43 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-c is pressed
WM_COPY;
Sleep(500);
OpenClipboard(NULL);
char* buffer;
buffer = (char*)GetClipboardData(CF_TEXT);
CloseClipboard();
clipboardQueue.push_back(buffer);
cout << buffer << " copied!\n";
cout << "clipboard size: " << clipboardQueue.size() << "\n";
}
else if (p->vkCode == 0x56 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-v is pressed
if (clipboardQueue.size() > 0) {
const char* output = clipboardQueue[0];
const size_t len = strlen(output) + 1;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), output, len);
GlobalUnlock(hMem);
OpenClipboard(0);
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
CloseClipboard();
WM_PASTE;
clipboardQueue.erase(clipboardQueue.begin());
cout << output << " pasted!\n";
cout << "clipboard size: " << clipboardQueue.size() << "\n";
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
OpenClipboard(NULL);
EmptyClipboard();
CloseClipboard();
HHOOK keyBoard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, NULL);
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(keyBoard);
}
Using this code when copying "one, two, three, four, five" my outputs seem to be random with occassional missing keys entirely:
three
three
three
?
five
one
?
three
?
five
?
four
four
four
five
Key edits:
When copy data to clipboard using ctrl + c there will sent a WM_CLIPBOARDUPDATE message which you can use to monitor ctrl + c operations. But there is no related message to monitor paste control + v operation so I keep hook part for control + v.
I can reproduce "outputs seem to be random" issue and solve it using array instead of std::vector.
Create a message-only window if you don't need a interact UI.
Add a new custom clipboard format MY_CLIPBOARD_FORMAT to indicate this is set data cased WM_CLIPBOARDUPDATE message not actual control + v operation.
The following is just an example implement for your use case you can refer to:
#include <windows.h>
#define MAX_LOADSTRING 100
#define MY_CLIPBOARD_FORMAT (CF_PRIVATEFIRST + 1)
// Global Variables:
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
static int index = 0;
static char dataArry[10][10] = {};
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK LowLevelKeyboardProc(int, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
DWORD errorCode;
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_QUEUECLIPBOARDDATA, szWindowClass, MAX_LOADSTRING);
// Register window class
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = szWindowClass;
ATOM cls = RegisterClassExW(&wcex);
errorCode = GetLastError();
// Create a message-only window
HWND hWnd = CreateWindowEx(0, szWindowClass, szTitle, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
if (!hWnd)
{
errorCode = GetLastError();
return FALSE;
}
// Set keyboard hook
HHOOK keyBoard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, NULL);
// Register a clipboard format listener
if (!AddClipboardFormatListener(hWnd))
errorCode = GetLastError();
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (wParam == WM_KEYDOWN) {
if (p->vkCode == 0x56 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-v is pressed
if(index <= 0)
return CallNextHookEx(NULL, nCode, wParam, lParam);
static int i = 0;
if (i < index)
{
const char* output = dataArry[i];
const size_t len = strlen(output) + 1;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), output, len);
GlobalUnlock(hMem);
OpenClipboard(0);
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
// Set custom defined format to indicate paste operation
SetClipboardData(MY_CLIPBOARD_FORMAT, NULL);
CloseClipboard();
OutputDebugStringA("\n pasted!\n");
i++;
}
else
{
i = 0;
index = 0;
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
DWORD errorCode;
HANDLE clipObj = NULL;
char* lptstr = NULL;
switch (message)
{
case WM_CLIPBOARDUPDATE:
{
OutputDebugStringA("\nWM_CLIPBOARDUPDATE\n");
// Empty clipboard casue this WM_CLIPBOARDUPDATE, actually no new data copied
if (IsClipboardFormatAvailable(MY_CLIPBOARD_FORMAT))
break;
if (!IsClipboardFormatAvailable(CF_TEXT))
break;
if (!OpenClipboard(hWnd))
{
errorCode = GetLastError();
break;
}
clipObj = GetClipboardData(CF_TEXT);
if(NULL == clipObj)
{
errorCode = GetLastError();
break;
}
lptstr = (char*)GlobalLock(clipObj);
if (lptstr != NULL)
{
OutputDebugStringA(lptstr);
memcpy(dataArry[index++], lptstr, strlen(lptstr));
GlobalUnlock(lptstr);
}
CloseClipboard();
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
The window title in the title bar is not setting to the variable and string i assign it.
I have show my code below but the problem is app::Window * wnd = new app::Window(L"Window Title"); constructor does seem to be 'tstring mWindowName;' but this mhWnd = CreateWindowEx(NULL, className.c_str(), mWindowName.c_str(), WS_OVERLAPPEDWINDOW, 100, 200, mScreenWidth, mScreenHeight, nullptr, nullptr, mhInstance, this); is not setting the title.
Window.h
#ifndef _ST_Window_H_
#define _ST_Window_H_
// include files
//#include "s-window.h"
#include "s-platform.h"
#include "s-safe-delete-and-release.h"
#include "s-iostream.h"
#include "s-strings.h"
#ifndef _WINDOWS_
#include <windows.h>
#endif //_WINDOWS_
namespace app
{
class Window
{
protected:
HINSTANCE mhInstance;
HWND mhWnd;
tstring mWindowName;
bool mRunState;
long int mScreenWidth;
long int mScreenHeight;
public:
Window(void);
Window(tstring windowName);
~Window(void);
int Setup(long int width, long int height);
LRESULT MessageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int Run(void);
inline HINSTANCE GetInstance(void) { return mhInstance; }
inline HWND GetHwnd(void) { return mhWnd; }
inline long GetWidth(void) { return mScreenWidth; }
inline long GetHeight(void) { return mScreenHeight; }
inline tstring GetWindowName(void) { return mWindowName; }
inline bool GetRunState(void) { return mRunState; }
protected:
int Create(void);
};
}
#endif //!_ST_Window_H_
Window.cpp
// include files
#include "sit-window.h"
using namespace std;
namespace app
{
Window::Window(void) : mhInstance(GetModuleHandle(0)), mhWnd(nullptr), mWindowName(nullptr),
mRunState(true), mScreenWidth(0), mScreenHeight(0)
{
}
Window::Window(tstring windowName) : mhInstance(GetModuleHandle(0)), mhWnd(nullptr),
mWindowName(windowName), mRunState(true), mScreenWidth(0), mScreenHeight(0)
{
}
Window::~Window(void)
{
}
int Window::Setup(long int width, long int height)
{
mScreenWidth = width;
mScreenHeight = height;
return Create();
}
LRESULT Window::MessageProc(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);
}
}
LRESULT CALLBACK Window::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Window * wnd;
if (msg == WM_NCCREATE)
{
CREATESTRUCT * pcs = (CREATESTRUCT*)lParam;
wnd = (Window*)pcs->lpCreateParams;
wnd->mhWnd = hwnd;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pcs->lpCreateParams);
return TRUE;
}
else
{
wnd = (Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
if (wnd)
return wnd->MessageProc(hwnd, msg, wParam, lParam);
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int Window::Run(void)
{
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
};
int Window::Create(void) {
WNDCLASSEX wnd;
SecureZeroMemory(&wnd, sizeof(WNDCLASSEX));
wnd.cbClsExtra = NULL;
wnd.cbSize = sizeof(WNDCLASSEX);
wnd.cbWndExtra = NULL;
wnd.hbrBackground = (HBRUSH)(COLOR_WINDOW + 3);
wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wnd.hInstance = mhInstance;
wnd.lpfnWndProc = WindowProc;
tstring className = mWindowName;
className.append(L" - WndCls");
wnd.lpszClassName = className.c_str();
wnd.lpszMenuName = nullptr;
wnd.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
if (!RegisterClassEx(&wnd))
{
std::wcout << L"Window class not registered!" << std::endl;
mRunState = false;
return 0x0;
}
RECT rect = { 0, 0, mScreenWidth, mScreenHeight };
if (!AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, NULL))
{
std::wcout << L"Failed to adjust window rect!" << std::endl;
mRunState = false;
return 0x0;
}
else
{
mScreenWidth = rect.right;
mScreenHeight = rect.bottom;
}
mhWnd = CreateWindowEx(NULL, className.c_str(), mWindowName.c_str(),
WS_OVERLAPPEDWINDOW, 100, 200, mScreenWidth, mScreenHeight,
nullptr, nullptr, mhInstance, this);
if (!mhWnd)
{
std::wcout << L"Window not created!" << std::endl;
mRunState = false;
return 0x0;
}
if (ShowWindow(mhWnd, SW_SHOW))
{
std::wcout << L"Failed to show window!" << std::endl;
mRunState = false;
return 0x0;
}
if (!UpdateWindow(mhWnd))
{
std::wcout << L"Failed to update window!" << std::endl;
mRunState = false;
return 0x0;
}
if (!SetForegroundWindow(mhWnd))
{
std::wcout << L"Failed to set to foreground!" << std::endl;
mRunState = false;
return 0x0;
}
return 0x0;
}
}
Main.cpp
// include files
//#include "s-safe-delete-and-release.h"
//#include "s-window.h"
#include "sit-window.h"
#include <iostream>
#include <string>
#include <windows.h>
#include <assert.h>
#pragma comment(lib, "serenity-core.lib")
// namespaces
using namespace std;
// statics
//long int srnty::Window::mScreenWidth = 1024;
//long int srnty::Window::mScreenHeight = 768;
// win main entry point
namespace win {
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
wcout << L"WinMain() called..." << endl;
app::Window * wnd = new app::Window(L"Window Title");
wnd->Setup(1024, 768);
int result = wnd->Run();
SafeDelete(wnd);
return result;
}
}
// main entry point
int main(int argv, char argc[])
{
// detect memory leaks in the application
#if defined(DEBUG) | defined(_DEBUG)
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetBreakAlloc(0);
int mlCount = _CrtDumpMemoryLeaks();
wcout << L"Number of memory Leaks: " << to_wstring(mlCount) << endl;
assert(mlCount == 0);
#endif
wcout << L"main() called..." << endl;
win::WinMain(GetModuleHandle(0), nullptr, nullptr, SW_SHOW);
wchar_t title[1024];
wchar_t titleBuffer[1024];
GetConsoleTitle(titleBuffer, 1024);
//wsprintf(title, L"%d", GetCurrentProcessId());
SetConsoleTitle(title);
Sleep(40);
HWND hwndFound = FindWindow(NULL, title);
SetForegroundWindow(hwndFound);
system("pause");
return 0x0;
}
I expect tstring mWindowName; to set the window Title in the title bar when used here mhWnd = CreateWindowEx(NULL, className.c_str(), mWindowName.c_str(), WS_OVERLAPPEDWINDOW, 100, 200, mScreenWidth, mScreenHeight, nullptr, nullptr, mhInstance, this);. The initialization of the tstring mWindowName; is through the constructor in Main.cpp app::Window * wnd = new app::Window(L"Window Title");
As Raymond Chen above clearly pointed out. This was an oversight on my behalf.
In the Window.cpp file LRESULT CALLBACK Window::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) never returned control the DefWindowProc function there for the never sets the title.
The fucntion should look like this:
LRESULT CALLBACK Window::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Window * wnd;
if (msg == WM_NCCREATE)
{
CREATESTRUCT * pcs = (CREATESTRUCT*)lParam;
wnd = (Window*)pcs->lpCreateParams;
wnd->mhWnd = hwnd;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pcs->lpCreateParams);
//return TRUE;
return DefWindowProc(hwnd, msg, wParam, lParam);
}
else
{
wnd = (Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
if (wnd)
return wnd->MessageProc(hwnd, msg, wParam, lParam);
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Thank you i hope this helps someone else.