I am fresh off from learning C++ and to learn winapi, I am doing the Forgers Win32 API tutorial.
Here is my code:
//MyControl.h
#pragma once
#include <windows.h>
#include "resource.h"
BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
BOOL BrushExists(HBRUSH hBrush);
-------------------------------------------------------
//MyControl.cpp
#include "MyControl.h"
HBRUSH g_hbrBackground = NULL;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
return (int)DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC)DlgProc);
}
BOOL BrushExists(HBRUSH hBrush) // I added this to better understand what is happening
{
if (hBrush)
return TRUE;
else
return FALSE;
}
BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_INITDIALOG:
{
g_hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
//... Other code skipped copy pasting ...
}
break;
case WM_COMMAND:
//... Other code skipped copy pasting ...
break;
case WM_CTLCOLORDLG:
return (LONG_PTR)g_hbrBackground; // Where casting happens
// return BrushExists(g_hbrBackground); // Tried this to understand things
break;
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(255, 255, 255));
SetBkMode(hdcStatic, TRANSPARENT);
return (LONG_PTR)g_hbrBackground; // Where casting happens
// return BrushExists(g_hbrBackground); // Tried this to understand things
}
break;
//... Other code skipped copy pasting ...
}
The code compiles and gives the warning: C4244: 'return': conversion from 'LONG_PTR' to 'BOOL', possible loss of data
The casting works and the dialog box is colored right as expected:
Black colored dialog.
My question: What happens in the background when HBRUSH is returned as a LONG_PTR from a function (DLGPROC) that returns BOOL? My assumption from reading C++ was that if the LONG_PTR is non-zero then the BOOL returned is TRUE and if LONG_PTR is zero then the BOOL returned is FALSE. To check this I created the function BOOL BrushExists(HBRUSH hBrush);// See code. Using this function to check for the HBRUSH and return TRUE, compiles without warnings and runs without error. But the coloring of the Dialog box does not happen:
Black color missing.
So my assumption is wrong. The LONG_PTR seems to be evaluated by the win32 API as a number instead of as a BOOL. Can someone explain to me how this is happening?
Note that it's BOOL and not bool. With the Windows SDK, BOOL is a typedef for int, which can store a 32-bit value - it's not a simple boolean that can only store true or false.
This is a kludge in the API basically. In 32 bit Windows, a brush handle fits in a 32 bit value, and even though it's ugly and potentially confusing, it's "safe" to return a brush handle cast as a BOOL (and you had to cast it, since that's what DialogProc was defined as returning).
Once Windows gained 64 bit support this situation obviously wasn't acceptable - in this example, brush handles (which are pointers) are 64 bits in size - casting them to a 32-bit type isn't safe.
Therefore, the definition of DialogProc was changed to return INT_PTR rather than BOOL. This is typedefed to 32-bits in x86 and 64-bits in x64. The example code you've used obviously pre-dates this change, but all new code should use the correct definition of DialogProc as returning INT_PTR.
BOOL is nothing but int typedef'd.
LONG_PTR may be either long int or __int64 - depending on platform chosen.
From header:
#ifdef _WIN64
typedef __int64 LONG_PTR;
#else
typedef long LONG_PTR;
#endif
You seem to be building the project as x64 compiler, and hence BOOL to LONG_PTR (essentially int to int64) is giving you warning.
Note that int and long are essentially same on Visual C++/Windows.
Related
For my college project I am developing a solution to distinguish between mouse user data from a person with Parkinson's compared to a healthy person. For which I need mouse data, ideally raw.
I presume I have misunderstood how to collect raw mouse input from the WM_INPUT message but I cannot figure it out.
I have been looking at the following thread: How to accurately measure mouse movement in inches or centimetres for a mouse with a known DPI
and Mouse input libraries on github all of which seem to easily catch a WM_INPUT message whose lParam is a handle to some RawInputData with something like this:
GetMessage(&msg, GetActiveWindow(), WM_INPUT, 0);
if (msg.message == WM_INPUT){ .....
And then retreiving the lParam from the message and collecting the data associated with that handle with:
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
However when I call GetMessage in my main loop, the function never exits!
Consequently there is no way (that i know of) for me to get a handle to the RawInputData. Especially since the MSDN page just assumes you have the lParam already.
In summary I need a method of getting an lParam to pass to the GetRawInputData function which will remain active whether the program is running in the active window of not.
I'm running this code in a blank C++ CLR project in Visual Studio with the "winuser.h" library.
#include "stdafx.h"
#include "Windows.h"
#include "winuser.h"
#ifndef HID_USAGE_PAGE_GENERIC
#define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01)
#endif
#ifndef HID_USAGE_GENERIC_MOUSE
#define HID_USAGE_GENERIC_MOUSE ((USHORT) 0x02)
#endif
int main(array<System::String ^> ^args)
{
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
Rid[0].dwFlags = 0; //ideally RIDEV_INPUTSINK but that prevents registration
Rid[0].hwndTarget = GetActiveWindow(); //ideally this would be Null to be independent of the active window
if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
//registration failed. Call GetLastError for the cause of the error
Console::WriteLine("Registration Error");
}
MSG msg;
while (true) {
while (GetMessage(&msg, GetActiveWindow(), WM_INPUT, 0) != 0) { //this command is never completed
DispatchMessage(&msg); //this line is never ran
}
if (msg.message == WM_INPUT) {
Console::WriteLine("caught a message!!!");
}
}
}
Issue solved after much more research I found the winAPI walk through which I followed fixing the issue above by adding an:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE unused, PSTR cmd, int show) {.....}
Function to register devices and create a window then call GetMessage which calls LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {....} with the parameters occupied by the message ID,WParam and LParam corresponding the message event.
For anyone stuck with a similar issue follow this MSDN guide: https://msdn.microsoft.com/en-us/library/bb384843.aspx
I am trying to use C++11 to solve my favorite pointer problem
LRESULT CALLBACK renderMan::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
//some code
WNDPROC crazy = bind(&renderMan::WindowProc,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4);
The error
1>renderman.cpp(50): error C2440: 'initializing' : cannot convert from 'std::_Bind<_Forced,_Ret,_Fun,_V0_t,_V1_t,_V2_t,_V3_t,_V4_t,_V5_t,<unnamed-symbol>>' to 'WNDPROC'
1> with
1> [
1> _Forced=true,
1> _Ret=LRESULT,
1> _Fun=std::_Pmf_wrap<LRESULT (__cdecl glSurface::* )(HWND,UINT,WPARAM,LPARAM),LRESULT,glSurface,HWND,UINT,WPARAM,LPARAM,std::_Nil,std::_Nil,std::_Nil>,
1> _V0_t=glSurface *const ,
1> _V1_t=std::_Ph<1> &,
1> _V2_t=std::_Ph<2> &,
1> _V3_t=std::_Ph<3> &,
1> _V4_t=std::_Ph<4> &,
1> _V5_t=std::_Nil,
1> <unnamed-symbol>=std::_Nil
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
The Problem
A WNDPROC is a pointer to a function with a certain signature using the __stdcall calling convention.
std::bind returns a function object not a function pointer. Although, at the source code level, the function object can be used almost identically to a function pointer, the fact remains that it is a completely different type. No amount of casting will solve this.
Since you're binding a this pointer with the renderMan::WindowProc method, it's clear that renderMan::WindowProc is not a static member function, and thus it uses the thiscall calling convention. So even if you could get a pointer to it and hand it to Windows, Windows wouldn't call it with the right calling convention.
Solutions
The most common way to handle this is to have a nonmember function (or static member function) registered as the WNDPROC. That function looks up the this pointer associated with the window, and forwards it to your member function.
LRESULT CALLBACK WndProcHelper(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
renderMan *that = LookUpPointer(hwnd);
assert(that != nullptr);
return that->WndProc(hwnd, msg, wp, lp);
}
The details of LookUpPointer will vary depending on your approach. It sounds like you solved it just by having a global variable and thus just one window instance.
If you need multiple windows instantiated from this window class, you could maintain a global (or class-static) table mapping the HWNDs to the renderMan pointers. When you create a new instance, you add it to the table, and then you have a simple implementation for LookUpPointer:
std::map<HWND, renderMan*> g_windows;
renderMan *LookUpPointer(HWND hwnd) {
// If there isn't an entry for hwnd in the map, then this will
// will create one, associating it with nullptr.
return g_windows[hwnd];
}
This can have some chicken and egg problems, though, since you will get some messages during the CreateWindow call, before you've gotten the HWND back and had a chance to add it and the pointer to the map. For example:
// ... inside a renderMan constructor ...
m_hwnd = CreateWindow(L"renderMan", /* ... */);
g_windows[m_hwnd] = this; // already too late for some messages
Another common approach, which solves the chicken and egg problem, is to stash the renderMan pointer in the creation parameters, and have special logic in your WndProcHelper to add it to the map during creation.
// ... inside the renderMan constructor ...
m_hwnd = CreateWindow(L"renderMan", /* ... */, reinterpret_cast<LPVOID>(this));
// ... and then ...
LRESULT CALLBACK WndProcHelper(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
static std::map<HWND, renderMan*> windows; // still static, but not global :-)
LRESULT result = 0;
renderMan *that = nullptr;
if (msg == WM_NCCREATE) {
auto pCreateStruct = reinterpret_cast<const CREATESTRUCT*>(lp);
that = reinterpret_cast<renderMan*>(pCreateStruct->lpCreateParams);
windows[hwnd] = that;
} else {
that = windows[hwnd];
}
if (that != nullptr) {
result = that->WndProc(hwnd, msg, wp, lp);
}
if (msg == WM_NCCDESTROY) {
windows.erase(hwnd);
}
return result;
}
Caution: This is simplistic code without enough error checking for the purposes of illustrating the idea. A clean and complete implementation would handle errors more gracefully, log unexpected things (like missing entries), etc.
C API's with callbacks almost always provide a "user data" field for this purpose -- passing your own context structure or object (i.e. the 'this' pointer) through to the callback.
In this case, the userdata does exist, which means there's no need for any std::map shenanigans, however it is kind of hidden away. The APIs that you're looking for are:
SetWindowLongPtr( hwnd, GWLP_USERDATA, your_user_data )
your_user_data = GetWindowLongPtr( hwnd, GWLP_USERDATA )
WNDPROC is a function pointer while the result of bind is a function object. and as the compiler says, it can´t be converted to WNDPROC.
you could do:
auto crazy = bind(.....)
std::function<LRESULT CALLBACK(HWND, UINT, WPARAM, LPARAM)> crazy = bind(...)
but i guess that doesn´t solve your problem. i think there´s no way to do this without a free function. maybe like this:
std::function<LRESULT CALLBACK(HWND, UINT, WPARAM, LPARAM)> crazy;
LRESULT CALLBACK myWindowProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
{
if(!crazy)
return (LRESULT)nullptr;
return crazy(hwnd,Msg,wParam,lParam)
}
//and then somewhere in your renderMan:
crazy = bind(&renderMan::WindowProc,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4);
// wherever you want:
SetWindowLongA( hwnd, GWL_WNDPROC, ( LONG )myWindowProc );
The solution was to use a global variable. That way the constructor binds the this variable to another variable like that. This works for a singleton pattern, although I feel my initial question remains unanswered.
I am writing a dll which is a COM wrapper for another dll (the inner dll) without COM support. The inner dll performs a lengthy computation and lets the outer dll know how progress is going via a callback function. The outer dll just makes the functions visible over COM.
However, I need the outer dll to pop up a progress bar dialog (the COM client I'm serving can't do this itself for various reasons). So how do I go about doing that? All examples I have seen so far revolve around Win32 apps which have a WinMain entry point; what can be done if we're already in a dll call when the dialog is needed?
I'm new to windows GUI programming, so quite out of my depth here. The existing code is included below - specific suggestions on what to call where would be appreciated. I'm guessing I may need to fire off a second thread to refresh the progress dialog.
Inner dll .h file (for implicit linking):
#define INNER_API extern "C" __declspec(dllimport)
//create calculation, passing callbacks for warning messages and progress bar
INNER_API Calculation* __stdcall calc_create(...blah...,
int (__cdecl *set_progressor_callback)(long),
int (__cdecl *print_warning_callback)(const char*));
INNER_API void __stdcall calc_run(Calculation *c);
Then in the outer dll, the com wrapper, ComWrapperObject.cpp:
int my_progressor_callback(long progress)
{
//set progressor to equal progress, but how?
return 0;
}
STDMETHODIMP ComWrapperObject::do_calculation()
{
//fire up progress bar and message window here, but how?
Calculation *calc = calc_create(...blah..., &my_progressor_callback);
calc_run(calc);
//wait for user to dismiss message window, but how?
return S_OK;
}
I'm posting a new answer which is more relevant to your updated question (and in order to be eligible for the bounty). Consider first this minimal source for a regular executable which contains a progress bar:
#include <Windows.h>
#include <CommCtrl.h>
#pragma comment(lib, "Comctl32.lib")
#include "resource.h"
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#define PROGRESSBAR_TIMER_ID 1
/*
* This callback is invoked each time the main window receives a message.
*/
INT_PTR CALLBACK DialogFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg) {
case WM_INITDIALOG: {
/*
* Fire a timer event each second.
*/
SetTimer(hwndDlg, PROGRESSBAR_TIMER_ID, 1000, NULL);
break;
}
case WM_TIMER: {
/*
* Catch the timer event that is fired each second. Increment the progress
* bar by 10% each time.
*/
HWND hwndProgressBar = GetDlgItem(hwndDlg, IDC_PROGRESS1);
UINT iPos = SendMessage(hwndProgressBar, PBM_GETPOS, 0, 0);
/*
* If the position is already full then kill the timer. Else increment the
* progress bar.
*/
if(iPos >= 100) {
KillTimer(hwndDlg, PROGRESSBAR_TIMER_ID);
} else {
SendMessage(hwndProgressBar, PBM_SETPOS, iPos + 10, 0);
}
break;
}
case WM_CLOSE:
EndDialog(hwndDlg, 0);
break;
default:
return FALSE;
}
return TRUE;
}
BOOL LaunchGUI(HINSTANCE hInstance)
{
return DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogFunc) == 0;
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
/*
* Initialise the common controls DLL.
*/
INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof(iccex);
iccex.dwICC = ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES;
if(!InitCommonControlsEx(&iccex)) {
MessageBox(NULL, L"Problem initialising common controls DLL.", NULL, MB_OK);
return -1;
}
/*
* Launches the main GUI window.
*/
LaunchGUI(hInstance);
return ERROR_SUCCESS;
}
If you like, I can post the relevant .rc resource file for this program although the code is mostly for you to gain the correct conceptual understanding. So to quickly summarise, this program:
Contains a single dialog containing a single progress bar
Sets a timer to fire each second
Each time the timer fires, the timer message triggers the progress bar to be updated
Graphically, it looks like this:
Your question is how to increment this bar from a DLL instead. What you need to do is to allow some way for the DLL to communicate with the window containing the progress bar. I'm not quite sure how you are loading the DLL, but this is the approach I would take assuming it is done through DLL injection:
Load/inject the DLL into the target
Have the DLL export some initialisation routine allowing it to receive information about the injector/client process.
Use GetProcAddress and CreateRemoteThread from the client to invoke this initialisation routine.
In the DLL, use the received information to get the HWND of the client.
Concretely, the intialisation routine would look like this:
HWND hwndClient = NULL;
BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam)
{
DWORD dwPID;
GetWindowThreadProcessId(hwnd, &dwPID);
if(dwPID == lParam) {
hwndClient = hwnd;
}
}
/*
* This code assumes the client has only one window. Given a PID, it populates
* a global to hold the window handle associated with the PID.
*/
DWORD WINAPI ReceiveClientPID(LPVOID dwPID)
{
EnumWindows(EnumProc, (LPARAM)dwPID);
}
The client code might be something like this:
/*
* Depending on your method of injection, you should have a handle to the
* target process as well as a HMODULE of the injected DLL.
*/
void InitDLL(HANDLE hProcess, HMODULE hModule)
{
FARPROC lpInit = GetProcAddress(hModule, "ReceiveClientPID");
HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL,
(LPTHREAD_START_ROUTINE)lpInit, (LPVOID)GetCurrentProcessId(), NULL, NULL);
if(hThread == NULL) {
MessageBox(NULL, L"Problem calling init routine in DLL", NULL, MB_OK);
} else {
CloseHandle(hThread);
}
}
So now you have the HWND of the client in the DLL and hence a way for you to do the communication. You can then specify a custom message in the client to change the progress bar:
/*
* The new progress position can be passed in wParam.
*/
#define WM_UPDATE_PROGRESS_BAR (WM_APP + 1)
Also add the corresponding case in the DialogFunc (we can remove the WM_TIMER code now because that was only there to demonstrate how to interact with progress bars):
case WM_UPDATE_PROGRESS_BAR:
SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS1), PBM_SETPOS, wParam, 0);
break;
And now to trigger changes in the progress bar of the client, the DLL simply has to do:
SendMessage(hwndClient, WM_UPDATE_PROGRESS_BAR, ..., 0);
Note that WM_UPDATE_PROGRESS_BAR needs to be redefined in the DLL as well.
To fit this all in with your current code:
/*
* Assumed progress is between 0 and 100. Otherwise it has to be
* normalised so this is the case (or the range of the progress bar
* in the client has to be changed).
*/
int my_progressor_callback(long progress)
{
SendMessage(hwndClient, WM_UPDATE_PROGRESS_BAR, progress, 0);
return 0;
}
Since you state that the DLL has no GUI and the client handles all the user interaction, why don't you send the progress information to the client instead and have it displayed there?
If you want to display the dialog in the DLL, you do so in exactly the same way as you would within a regular executable. There is absolutely no difference. If you want the DLL to continue working while it updates the progress bar, you can just kick off a new thread with CreateThread.
If you show some code, we'll be able to help you more directly.
Good day,
I have been using JNA for a while to interact with the Windows API and now I am stuck when creating a window. As far as I have done the following:
1. Have created a child window of an existing window and obtained a valid handler to it.
2. Understood that every window in Windows has a non-stop message-dispatch loop.
3. Understood that the best way to include my window in the message-dispatch loop is to use something like the following code (not mine, but that is what I would do as well):
final LONG_PTR prevWndProc = new LONG_PTR(User32.INSTANCE.GetWindowLong(hwnd, User32.GWL_WNDPROC)); //this is to obtain a pointer to the WNDPROC of the parent window, which we are going to need later
wndProcCallbackListener = new WndProcCallbackListener()
{
public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam)
{
if (uMsg == WTSAPI.WM_POWERBROADCAST)
{
System.out.println("WM_POWERBROADCAST Event: hWnd="+hwnd+", uMsg="+uMsg+", uParam="+uParam+", lParam="+lParam);
}
else if (uMsg == WTSAPI.WTS_SESSION_CHANGE)
{
System.out.println("WTS_SESSION_CHANGE Event: hWnd="+hwnd+", uMsg="+uMsg+", uParam="+uParam+", lParam="+lParam);
}
//Call the window's actual WndProc so the events get processed.
return User32.INSTANCE.CallWindowProc(prevWndProc, hWnd, uMsg, uParam, lParam);
}
};
//Set the WndProc function to use our callback listener instead of the window's one.
int result = User32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, wndProcCallbackListener);
However, my problem is when I call the GetWindowLong() for the parent window (my first line of code) I get a 0 for the pointer which indicated the function did not complete successfully. A subsequent call to GetLastError() and a quick check in the error codes give me an 'Access is denied' error. This, of course, is logical, since I am trying from my own thread to access the address of the WNDPROC of another, but I was wondering if there is any way (there should be, of course) to circumvent that.
Any pointers? (pun intended)
Do not use GetLastError() after a JNA call. JNA & JNI may call other APIs that may change the last error. Declare SetWindowLong with the clause throws LastErrorException, like this:
int SetWindowLongA(int hWnd, int nIndex, WndProcCallbackListener dwNewLong)
throws LastErrorException;
Notice the 'A' after the name. It makes explicit use of ANSI version. You could use SetWindowLongW as well.
Make sure your callback implements both Callback and StdCall. I prefer using primitive types as much as possible, because this makes mapping fast and obvious to JNA:
public interface WndProcCallbackListener extends Callback, StdCall {
int callback(int hWnd, int Msg, int wParam, int lParam);
}
I have this class here that I made based on another one I had. It is supposed to handle the whole creating windows and stuff, but it seems to be getting into a hang now. The older version used to work fine, I don't know WHAT I may have forgotten to add to this one that might be causing it to hang like this.
This is the message loop:
int Window::HandleMessages()
{
while(GetMessage(&this->windat.msgs, NULL, 0, 0))
{
TranslateMessage(&this->windat.msgs);
DispatchMessage(&this->windat.msgs);
}
return this->windat.msgs.wParam;
}
Pretty basic stuff, I don't know why, but it will simply hang... When I run the program, it'll just show me an empty prompt window, and by testing, I got it to show a message box if I used it before the while loop, but inside it doesn't work. I've been trying to compare both this class and the older one and haven't figured out what might be wrong with this. Could anyone tell me what could possibly trigger this behaviour?
Thanks
OK, now this left me pretty confused. By messing around with GetLastError, it seems that it is returning error 2 (file not found) ANYWHERE I put it, even if right at the start of the Main, before I instantiate my Window class. If I call GetLastError anytime after CreateWindowEx, it'll return an error like 1047 or something, about class not found or something. HWND becomes NULL too
Here is the code for the main.cpp:
#include "SimpWin/SimpWin.h"
#include <stdio.h>
// Make the class name into a global variable
char szClassName[] = "WindowsApp";
void ErrorExit(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
sprintf((char*)lpDisplayBuf,
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(dw);
}
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
ErrorExit(TEXT("CreateWindowEx"));
Window* win = Window::CreateWindowClass(hThisInstance, szClassName, WindowProcedure);
if(!win->Register())
{
return 0;
}
win->Show(nFunsterStil);
int res = win->HandleMessages();
delete win;
return res;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc (hwnd, message, wParam, lParam);
}
This here, is the code for the Window::Register function:
int Window::Register()
{
if(this->windat.wincl.hIcon == NULL)
{
this->windat.wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
}
if(this->windat.wincl.hIconSm == NULL)
{
this->windat.wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
}
if(!RegisterClassEx(&this->windat.wincl))
{
return 0;
}
this->windat.hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
(char*) this->windat.sName, /* Classname */
(char*) this->windat.sTitle, /* Title Text */
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
this->windat.cDimension.width, /* The programs width */
this->windat.cDimension.height, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
this->windat.hInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
return 1;
}
I'm lost here, I don't know why the eff this is going on... :/
Use PeekMessage instead of GetMessage.
Check the return value to GetMessage() - your while loop won't exit if there are errors. It should look like this:
while (GetMessage(&this->windat.msgs, NULL, 0, 0) > 0)
{
...
}
Well, I finally got it working! :D
It actually had to do with a completely unrelated class I had here. It is a String class (which descended from Array) which I made, and the copy function had a bug, it would copy the character array I passed to it, but would not update the length field of the class...
That copy function would be called whenever I had to set the class to a value through operator=. The length is required for the operator char* to convert the class to c-format string. I'd use that cast when passing the ClassName and Title values to CreateWindowEx, and it would return me an array of 0 chars, and that's where hell happened.
Now I fixed that lib up, and it's working fine now. Thanks :D
Even though it's pretty old... from MSDN on GetMessage:
Unlike GetMessage, the PeekMessage function does not wait for a message to be posted before returning.
That is, GetMessage waits for next message to become available. You treat this wait in progress as a freeze, supposedly because you did not actually have the intention to wait for messages.
Note that you can attach debugger at the time of supposed freeze, pause the execution and inspect the call stacks of the threads. Once you find your thread and its call stack and its GetMessage in progress on the stack - you isolate the problem well enough to know where to read on documented behavior.