Ambigous Pointers in Visual C++ - winapi

Hello everyone,
I am a novice to Win32 API programming in Visual C++. I am using Microsoft Visual Studio 2008 Professional Edition. I am facing a of bit confusion regarding pointers. Please note though I may be a novice to Windows programming, I am not a novice in C or C++ therefore I understand the concept of pointers well.
The pointer which is causing a problem is related with a date and time picker control in a dialog box. Now according to the msdn documentation the date and time picker communicates to the application using WM_NOTIFY messages and the LPARAM in the message will be the pointer to the NMHDR structure. That is-:
'A date and time picker (DTP) control sends notification codes when it receives user input or processes and reacts to callback fields. The parent of the control receives these notification codes in the form of WM_NOTIFY messages.'
Now I can access the NMHDR structure by just typecasting the LPARAM to a pointer of NMHDR when I receive an WM_NOTIFY message. That is as follows-:
case WM_NOTIFY:
if ((((NMHDR*)lparam)->idFrom == IDC_DATETIMEPICKER)&&
((NMHDR*)lparam)->code == DTN_DATETIMECHANGE)
{ LPNMDATETIMECHANGE lpChange=(LPNMDATETIMECHANGE)lparam;
DisplayTime(&(lpChange->st));
MessageBox(NULL,"wm_notify","test",MB_OK);
}
return TRUE;
But look at the fourth line of this code fragment. I am casting the same lparam, which I just casted to a NMHDR structure, into a NMDATETIMECHANGE structure.
My question is how is this possible ? How am I casting a single parameter into two different pointers that reference two different structures ? The NMHDR and LPNMDATETIMECHANGE structures are fundamentally different structures. You can check here-: NMHDR and NMDATETIMECHANGE
How is this possible? I know it is possible to store the value of a pointer in some other variable with a different data-type all together and again cast it back when we want to use it. But how is it possible to have a single pointer point to two different structures altogether ? I mean I don't think that the NMHDR and NMDATETIMECHANGE structures are the same entity in the memory so how can a single pointer reference both of them at the same time ? They have two different memory addresses altogether I hope? Oh, and please note that this code is tested, it works. My source code is as follows-:
#include <Windows.h>
#include <CommCtrl.h>
#include <cstdio>
#include "resource.h"
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DialogFunc(HWND, UINT, WPARAM, LPARAM);
VOID InitOptions(HWND);
VOID DisplayTime(SYSTEMTIME*);
char szWinName[]="Timer Main Window";
HWND hDlg=NULL;
HINSTANCE hInst;
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst,
LPSTR lpszArgs, int nWinMode)
{
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;
wndclass.cbSize=sizeof(WNDCLASSEX);
wndclass.hInstance=hThisInst;
wndclass.lpszClassName=szWinName;
wndclass.lpfnWndProc=WindowFunc;
wndclass.style=0;
wndclass.hIcon=LoadIcon(hThisInst,MAKEINTRESOURCE(IDI_ICON1));
wndclass.hIconSm=LoadIcon(hThisInst,MAKEINTRESOURCE(IDI_ICON2));
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.lpszMenuName=NULL;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hbrBackground=(HBRUSH) GetStockObject(LTGRAY_BRUSH);
if(!RegisterClassEx(&wndclass)) return 0;
InitCommonControls();
hInst=hThisInst;
hwnd=CreateWindow(
szWinName,
"Auto Timer (Work in progress)",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hThisInst,
NULL
);
while(GetMessage(&msg, NULL, 0, 0)>0)
{ if (!hDlg||!IsDialogMessage(hDlg,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wparam,
LPARAM lparam)
{
switch(message){
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE:
hDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_FORMVIEW),
hwnd,(DLGPROC)DialogFunc);
break;
default:
return DefWindowProc(hwnd,message,wparam,lparam);
}
return 0;
}
BOOL CALLBACK DialogFunc(HWND hwnd, UINT message,
WPARAM wparam, LPARAM lparam)
{
switch(message)
{
case WM_INITDIALOG:
SendMessage(hwnd,WM_SETICON, ICON_SMALL ,
(LPARAM)LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON2)));
return TRUE;
case WM_CTLCOLORSTATIC:
if (SendDlgItemMessage(hDlg,IDC_COMBO,CB_GETCOUNT,0,0)<6)
{
InitOptions(hDlg);
}
return (INT_PTR)GetStockObject(WHITE_BRUSH);
case WM_NOTIFY:
if ((((NMHDR*)lparam)->idFrom == IDC_DATETIMEPICKER)&&
((NMHDR*)lparam)->code == DTN_DATETIMECHANGE)
{ LPNMDATETIMECHANGE lpChange=(LPNMDATETIMECHANGE)lparam;
DisplayTime(&(lpChange->st));
MessageBox(NULL,"wm_notify","test",MB_OK);
}
return TRUE;
case WM_COMMAND:
switch LOWORD(wparam)
{ case IDC_BUTTON1:
/*
Button Code here.
*/
if (SendDlgItemMessage(hDlg,IDC_RADIO5,BM_GETSTATE,0,0)==BST_CHECKED)
{ MessageBox(NULL,"radio5","test",MB_OK);
}
return TRUE;
case IDC_RADIO5:
EnableWindow(GetDlgItem(hDlg,IDC_COMBO),TRUE);
EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER),FALSE);
EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER1),FALSE);
return TRUE;
case IDC_RADIO6:
EnableWindow(GetDlgItem(hDlg,IDC_COMBO),FALSE);
EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER),TRUE);
EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER1),TRUE);
return TRUE;
default:
return FALSE;
}
case WM_CLOSE:
DestroyWindow(hwnd);
hDlg=NULL;
PostQuitMessage(0);
return TRUE;
}
return FALSE;
}
VOID InitOptions(HWND hDlg){
SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("1 minute"));
SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("5 minutes"));
SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("10 minutes"));
SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("20 minutes"));
SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("30 minutes"));
SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("1 hour"));
SendDlgItemMessage(hDlg,IDC_COMBO,CB_SETCURSEL,0,0);
SendDlgItemMessage(hDlg,IDC_RADIO5,BM_SETCHECK,BST_CHECKED,0);
SendDlgItemMessage(hDlg,IDC_RADIO1,BM_SETCHECK,BST_CHECKED,0);
SendDlgItemMessage(hDlg,IDC_DATETIMEPICKER1,DTM_SETFORMAT,0,(LPARAM)"dd/MMM/yyyy");
EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER1),FALSE);
}
VOID DisplayTime(SYSTEMTIME *time)
{
char t[500];
sprintf_s(t,"Year=%d\n Month=%d\n Day=%d\n Hour=%d\n Minute=%d\n Seconds=%d\n",
time->wYear,time->wMonth,time->wDay,
time->wHour,time->wMinute,time->wSecond);
MessageBox(NULL,t,"Test",MB_OK);
}
My resource script is the following-:
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_FORMVIEW DIALOGEX 0, 0, 298, 178
STYLE DS_ABSALIGN | DS_SETFONT | DS_SETFOREGROUND | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW | WS_EX_NOACTIVATE
CAPTION "SR-Timer(Work in Progress)"
FONT 10, "Verdana", 400, 0, 0x0
BEGIN
GROUPBOX "Tasks",IDC_STATIC1,11,45,84,103,WS_GROUP,WS_EX_TRANSPARENT
CONTROL "ShutDown",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,19,63,44,10,WS_EX_TRANSPARENT
CONTROL "Restart",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,19,81,40,10,WS_EX_TRANSPARENT
CONTROL "Stand By",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,19,114,46,10,WS_EX_TRANSPARENT
CONTROL "Hibernate",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,19,130,48,10,WS_EX_TRANSPARENT
CONTROL "Log Off",IDC_RADIO7,"Button",BS_AUTORADIOBUTTON,19,98,44,9,WS_EX_TRANSPARENT
GROUPBOX "Timing",IDC_STATIC2,196,44,90,107,WS_GROUP,WS_EX_TRANSPARENT
CONTROL "Pre-set Time",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON,201,56,53,9,WS_EX_TRANSPARENT
GROUPBOX "Presets",IDC_STATIC3,206,65,68,30,0,WS_EX_TRANSPARENT
CONTROL "Specify Time",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON,201,97,54,9,WS_EX_TRANSPARENT
GROUPBOX "Time",IDC_STATIC4,208,106,67,42,0,WS_EX_TRANSPARENT
CONTROL "",IDC_DATETIMEPICKER,"SysDateTimePick32",DTS_RIGHTALIGN | DTS_UPDOWN | WS_DISABLED | WS_TABSTOP | 0x8,213,133,58,11,WS_EX_TRANSPARENT
PUSHBUTTON "Schedule Task",IDC_BUTTON1,184,159,104,14,BS_CENTER,WS_EX_TRANSPARENT
COMBOBOX IDC_COMBO,213,78,57,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP,WS_EX_TRANSPARENT
CONTROL "",IDC_DATETIMEPICKER1,"SysDateTimePick32",DTS_RIGHTALIGN | WS_TABSTOP,213,116,58,13,WS_EX_TRANSPARENT
CONTROL 118,IDC_STATIC,"Static",SS_BITMAP,0,0,299,178
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "Test.ico"
IDI_ICON2 ICON "small.ico"
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_FORMVIEW, DIALOG
BEGIN
BOTTOMMARGIN, 177
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
IDB_BITMAP1 BITMAP "time_back.bmp"
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
My resource header is the following-:
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Timer.rc
//
#define IDD_FORMVIEW 101
#define IDI_ICON1 109
#define IDI_ICON2 110
#define IDB_BITMAP1 118
#define IDC_DATETIMEPICKER 1002
#define IDC_RADIO1 1003
#define IDC_RADIO2 1004
#define IDC_RADIO3 1005
#define IDC_RADIO4 1006
#define IDC_BUTTON1 1007
#define IDC_RADIO5 1011
#define IDC_RADIO6 1013
#define IDC_COMBO 1015
#define IDC_STATIC1 1017
#define IDC_STATIC2 1018
#define IDC_STATIC3 1022
#define IDC_STATIC4 1023
#define IDC_COMBO1 1024
#define IDC_DATETIMEPICKER1 1025
#define IDC_RADIO7 1026
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 120
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1027
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
You can make your own VC++ project and test it out to see if I am telling the truth or not. If you are still not convinced then please give me your mail id and I will email you the entire project. Please I need help because this is a problem which goes against my basics of pointers in C. Thank You.

If you look closely, you'll see that NMDATETIMECHANGE contains a NMHDR as its first member, so it is effectively a derived class. (Not strictly a derived class because C doesn't have classes, but it's the C emulation of a derived class.) Casting to NMDATETIMECHANGE is therefore a downcast.
More formally, it's a CONTAINING_RECORD(NMDATETIMECHANGE, hdr, (NMHDR*)lparam) but that's a lot of typing, so most people shortcut it to the direct cast.

typedef struct tagNMDATETIMECHANGE {
NMHDR nmhdr;
DWORD dwFlags;
SYSTEMTIME st;
} NMDATETIMECHANGE, *LPNMDATETIMECHANGE;
Thats the definition of the NMDATETIMECHANGE structure. Note the first member is of type NMHDR . So if you use the pointer to NMDATETIMECHANGE structure you are effectively pointing to the base address of NMHDR. That is the reason you can typecast the LPARAM to NMHDR* and NMDATETIMECHANGE*.

Related

Trouble catching WM_INPUT message for lParam, to collect Raw Mouse Input

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

Understanding: conversion from long_ptr to bool possible loss of data

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.

What to #include for code about windows,raw mouse data

I find the following post very useful to do a project of my own. Here's the newbie question then: what must I include for this to work?
Link:
How to accurately measure mouse movement in inches or centimetres for a mouse with a known DPI
Content:
The following code registers the RAWINPUTDEVICE so it can be used in WM_INPUT.
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = hWnd;
RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]);
The following code acutally uses the Rid variable two determine how many pixels the mouse has moved since the last time WM_INPUT was initiated.
case WM_INPUT:
{
UINT dwSize = 40;
static BYTE lpb[40];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT,
lpb, &dwSize, sizeof(RAWINPUTHEADER));
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEMOUSE)
{
int xPosRelative = raw->data.mouse.lLastX; // Could be 1, or could be more than 1
int yPosRelative = raw->data.mouse.lLastY; // Could be 1, or could be more than 1!
}
break;
}
I just found it.
#include "hidusage.h"
here's some definitions it has
#define HID_USAGE_GENERIC_POINTER ((USAGE) 0x01)
#define HID_USAGE_GENERIC_MOUSE ((USAGE) 0x02)
#define HID_USAGE_GENERIC_JOYSTICK ((USAGE) 0x04)
#define HID_USAGE_GENERIC_GAMEPAD ((USAGE) 0x05)
#define HID_USAGE_GENERIC_KEYBOARD ((USAGE) 0x06)
#define HID_USAGE_GENERIC_KEYPAD ((USAGE) 0x07)
#define HID_USAGE_GENERIC_SYSTEM_CTL ((USAGE) 0x80)
typedef USHORT USAGE,*PUSAGE;
You need to include windows.h
...also the HID_USAGE_PAGE_GENERIC and HID_USAGE_GENERIC_MOUSE must be defined.
See MSDN..
#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
http://msdn.microsoft.com/en-gb/library/windows/desktop/ee418864%28v=vs.85%29.aspx

Easiest way to pop up a progress bar dialog from C++ dll (windows)

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.

#define _UNICODE not working with MinGW + CodeBlocks

usually i use visual studio, but i switched to mingw, i like to make my apps easily changeable from unicode and multi byte, in my mingw project i have my defines and includes like this:
#define WIN32_LEAN_AND_MEAN
#define WINVER 0x0700
#define _UNICODE
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#define WND_MAIN_CLASS _T("MainWindowFrame")
then i register and create my window e.g.
WNDCLASSEX wc;
...
wc.lpszClassName = WND_MAIN_CLASS;
RegisterClassEx(&wc);
hwnd = CreateWindowEx(0, WND_MAIN_CLASS, _T("Main Window"),
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInst, NULL);
but when i go to compile i get errors that it cannot convert wchar_t to CHAR* on the WNDCLASSEX lpszClassName and the CreateWindowEx on the Class name and window title.
if i right click and go to declaration of createwindowex and WNDCLASSEX, it comes up with these from winuser.h:
typedef WNDCLASSEXW WNDCLASSEX,*LPWNDCLASSEX,*PWNDCLASSEX;
#define CreateWindowEx CreateWindowExW
if i comment out the define _UNICODE it compiles and works with no problems
When compiling unicode apps you should probably define both UNICODE and _UNICODE. The windows headers use UNICODE and the MS C runtime uses _UNICODE

Resources