I was trying to implement mouse and keyboard support in my game engine using DirectXTK. It was quite simple for keyboard, but I have got a problem with implementing proper mouse support. I was following THIS for implementing mouse into my engine. This article from Microsoft wiki says that I have call SetWindow, before I will be able to change mouse mode from absolute to relative. It sounds easy, but when I try to do this like this:
auto mouse = std::make_unique<DirectX::Mouse>();
mouse->SetWindow(hwnd);
mouse->SetMode(DirectX::Mouse::Mode::MODE_RELATIVE);
I get an error:
E0135 class "DirectX::Mouse" has no member "SetWindow"
It looks like this method doesn't exist in Mouse class. It is weird, becuse if I remove this line with setting window it will compile, but I will fail in runtime due to this assertion in Mouse class:
assert(mWindow != nullptr);
So it is required to set window, but how can I do this, when this function doesn't exist? What's worse the article from wiki is not old, it's from 18 Apr 2019. Have anyone encountered this problem? How can I fix this?
A quick look at the header file and you'll see this
#if (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) && defined(WM_USER)
void __cdecl SetWindow(HWND window);
static void __cdecl ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam);
#endif
So it seems likely that you don't have WINAPI_FAMILY and/or WM_USER defined in a suitable way to enable the declaration of that method in the header file.
I believe WM_USER will be defined by #include <windows.h> so maybe all you need to do is place that include before #include <mouse.h>
Related
I am looking at MFC splitter window class override:
https://www.codeproject.com/Articles/6188/How-to-prevent-resizing-of-views-in-a-splitter-win
I had tested the override source code with WTL CSplitterWindow, but it doesn't worked.
i had modified the MainFrm.h using CSplitOverride instead of CSplitterWindow class.
when program start "api-ms-win-core-libraryloader-l1-2-0.dll missing.." popup error message shows.
windows 7 64bit os platform, 32 bit vs2015 build.
class CSplitOverride : public CSplitterWindow
{
public:
CSplitOverride() { }
protected:
BEGIN_MSG_MAP(CSplitOverride)
MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
END_MSG_MAP()
public:
LRESULT OnNcHitTest(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
return HTNOWHERE;
}
};
EDIT: i had been tried thickframe setting but no available. Jan S solution works like that i want.
Take a look at Michael Dunns excellent tutorial on splitter windows (this requires a few changes to get it to even compile in vs2013 though!)
This discussion on the WTL sourceforge site also may be useful
I think you are asking how you keep a pane a constant size when the main frame is resized? It depends on the alignment of the fixed pane
atlsplit.h defines the following extended styles
#define SPLIT_RIGHTALIGNED 0x00000004
#define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED
As Michael Dun says - "If none of those three styles are specified, the splitter defaults to being left- or top-aligned."
SPLIT_NONINTERACTIVE stops the user from resizing the pane
m_cxyMin hard codes the minimum size of the pane specified by the alignment
m_wndHorzSplit.SetSplitterExtendedStyle(SPLIT_BOTTOMALIGNED | SPLIT_NONINTERACTIVE);
m_wndHorzSplit.m_cxyMin = 150;
I started recently learning C++ and WinAPI, I want to be able to create my own programs
I am subclassing a button (into separate file, because I like things clean and organized - is that a bad idea?), because I want to have few of the kind with same parameters. I also want to draw it, and the question that pops to my mind is: wouldn't it be better to have it all in the class file? Meaning all parameters including custom draw. It is annoying to go to main file to change the looks and set all other parameters in the class file. I use codeblocks.
EDIT (explanation):
#include <Windows.h>
#include <Winuser.h>
#include "CustomButton.h"
/*global vars*/
WNDPROC CustomButton::CustomButtonLongPtr;
/*functions*/
LRESULT CALLBACK CustomButtonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
CustomButton * CustomButton::CreateCustomButton(HINSTANCE hInstance, HWND hwnd, int pos_x, int pos_y, int width, int height)
{
CustomButton * p_CustomButton = new CustomButton;
HWND customButton = CreateWindowEx(0, "BUTTON", "OK", WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, pos_x, pos_y, width, height, hwnd, (HMENU)200, (HINSTANCE)GetWindowLong(hwnd, GWLP_HINSTANCE), p_CustomButton);
if(customButton == NULL)
{
delete p_CustomButton;
MessageBox(NULL, "Problem creating the Search box.", "Error", 0);
return 0;
}
CustomButton::CustomButtonLongPtr = (WNDPROC)SetWindowLongPtr(customButton, GWLP_WNDPROC, (LONG_PTR)&CustomButton::CustomButtonProc);
return p_CustomButton;
}
I want to use WM_DRAWITEM for this button in CustomButtonProc and I am wondering why did the developers think that it would be smarted to allow to use it only in parent WinProc.
This is a little complicated to explain.
You're probably coming from a background where you plug a function into an outlet to handle events, something like
extern void onClicked(void);
button->OnClicked = onClicked;
And while it's fully possible for Windows to have done this from the start, you have to remember that Windows was originally designed to run on systems with severely limited memory, so it was important that controls not waste memory. And there are a lot of events you can get from a button:
void (*OnClicked)(void);
void (*OnDoubleClicked)(void);
void (*OnDisabled)(void);
void (*OnHighlight)(void);
void (*OnKillFocus)(void);
void (*OnPaint)(void);
void (*OnSetFocus)(void);
void (*OnUnhighlight)(void);
void (*OnUnpushed)(void);
HBRUSH (*OnCtlColorButton)(void);
Having these for every button in your program — that is, push buttons, checkboxes, radio buttons, and groupboxes — with most of them likely to be unused would just be a massive waste of memory.
Because Windows needs a way to communicate between the system and a window and between windows, Microsoft decided to create a message-passing interface where each message had a 16-bit code and two pointer-sized (originally one 32-bit and one 16-bit) parameters and a pointer-sized return value. And there aren't a lot of messages that Windows needs for itself, giving both window classes and the application a lot of real estate for using messages to communicate. So why not use a message to signal the event?
Using a message avoids the waste of memory while still allowing the button to pass data to and return data from its target window. So the logic follows that all a button would need to do is
/* this is not the correct syntax but let's use it for expository purposes */
#define BN_CLICKED someNumberHere
case WM_LBUTTONUP:
SendMessage(GetParent(hwnd), BN_CLICKED, hwnd);
break;
and the parent would handle that:
case BN_CLICKED:
if (whichButton == button1)
doButton1Stuff();
break;
No wasted memory, but still flexible and extensible. And even more importantly, also binary-compatible: if more events were added later, the size of the function pointer table would need to change, and newer programs that tried to use newer events on older systems would clobber random memory. With messages, these programs would just have dead code.
Now why send the message to the parent? If we view windows as communication endpoints, then this is obvious: you want the button to tell its parent that it was clicked because you're communicating that the button was clicked!
But more important, you didn't write the button's window procedure. Microsoft did, and they provide the same one to every program. If you could handle the message in the button procedure, where would you put it? You can't change the button procedure, after all.
(Nowadays we have something called "subclassing" which allows you to override a single window's window procedure to do custom processing. It's not used for event handling because it's more work than just sending up to the parent.)
All of this extends to custom draw; just substitute "custom draw" for "clicked" and it should still make sense. Hopefully this explanation was clear, even with that mental substitution.
If you want, you can write your own facility to handle events in the function pointer way. Keep a map of window handles to event functions and call a global dispatch function in all your window procedures to handle the event messages WM_COMMAND, WM_NOTIFY, and (for trackbars) WM_HSCROLL and WM_VSCROLL. How you do this is up to you, but think about whether you really want to do it this way; sometimes it's necessary, but sometimes it isn't. If you do, remember to provide a way to pass arbitrary data to the event function that's decided at event connection time, so the event handler can do something reasonable without relying on global state.
Thanks to comments by RemyLebeau and IInspectable I was able to also find solution to my frustration, which I am going to explain here for anybody else who's scratching their heads over this very issue.
This solution does not require VCL nor any component from Visual Studio and such.
First define your own custom message, in the way that you can reach it inside WndProc:
#define MY_DRAWITEM (WM_APP+1)
UINT uDrawButtonMsg = RegisterWindowMessage(_T("MY_DRAWITEM"));
Then find out what number it is assigned:
std::cout << uDrawButtonMsg; //for example 49648
And send this message from WndProc to your subclassed control from any message you wish, for example WM_DRAWITEM:
case WM_DRAWITEM:
{
::SendMessage(p_CustomButton->customButton, uDrawButtonMsg, wParam, lParam);
break;
}
And then in your subclass just catch the message by the 5 digit number you looked for while ago:
if(49648 == uMsg)
{
//do your DRAWITEM stuff here
}
Thanks to everybody who contributed to this article helping with exaplanation, tips and also historical background!
After following a tutorial to create a basic particle system, I began implementing AntTweakBar to get a basic UI going. This was going well, everything draws OK. But once I started adding the callback functions it started to go a little haywire, claiming that it's throwing this in the middle of a method definition:
Intellisense: expected a ';'
The method in question is:
void GLFWCALL OnMouseRight(int glfwButton, int glfwAction)
{
if( !TwEventMouseButtonGLFW(glfwButton, glfwAction) ) // Send event to AntTweakBar
{
if(glfwButton == GLFW_MOUSE_BUTTON_RIGHT)
computeMatricesFromInputs();
else
// Event has not been handled by AntTweakBar
// Do something if needed.
}
}
The error is apparently popping up between the name OnMouseRight and the following parentheses. How do I get rid of this error? I'm coding in OpenGL (using GLFW and GLEW) with C++ and I have been following the steps on this page on the AntTweakBar site. I have looked up most of the GLFW documentation already and not found much. Any help appreciated.
There is a missing statement after else which is causing the error:
if(glfwButton == GLFW_MOUSE_BUTTON_RIGHT)
computeMatricesFromInputs();
else
// ^ no statement here
You can add a semicolon as Intellisense suggests or an empty compound statement {}:
if(glfwButton == GLFW_MOUSE_BUTTON_RIGHT) {
computeMatricesFromInputs();
} else {
// Event has not been handled by AntTweakBar
// Do something if needed.
}
Right, after a long night's work at this problem and trawling through GLFW's documentation again I noticed that the problem lay with the macro GLFWCALL. C++ was treating it as a method in it's own right and as a result ignoring the actual method. GLFW's documentation explained why:
The GLFWCALL macro, which made callback functions use __stdcall on Windows, has been removed. GLFW is written in C, not Pascal. Removing this macro means there's one less thing for users of GLFW to remember, i.e. the requirement to mark all callback functions with GLFWCALL. It also simplifies the creation of DLLs and DLL link libraries, as there's no need to explicitly disable #n entry point suffixes.
On removing GLFWCALL and following the advice of #vitaut my program now handles the right mouse inputs correctly.
The question is like this:
I write a windows application in VS2005, building success. Then I transfer it to VS2008, when I build the program, there will be an error messsage shows:
error C4867: 'CGroupBox::CtlColor': function call missing argument list; use '&CGroupBox::CtlColor' to create a pointer to member
the message map is as follows:
BEGIN_MESSAGE_MAP(CGroupBox, CButton)
//{{AFX_MSG_MAP(CGroupBox)
ON_WM_PAINT()
ON_WM_CTLCOLOR_REFLECT()
//ON_WM_CTLCOLOR()
ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
the function is is as follows:
HBRUSH CGroupBox::CtlColor(CDC* pDC, UINT nCtlColor)
{
GetParent()->Invalidate();
return NULL;
}
but if I change to the ON_WM_CTLCOLOR() ,I can get a successful build.
The error message is because the signature of the message handler doesn't match the signature you're using. Look up the signatures for ON_WM_CTLCOLOR_REFLECT() and ON_WM_CTLCOLOR() on MSDN to get the correct ones.
As to the question in your title, some controls normally send their notification messages to their parent. Which is inconvenient, because every time you re-use that control, you need to change its parent window. Therefore MFC has 'reflection' support, which is basically a way of saying 'when you receive a notification from a child control, first try bouncing it back to that control to see if that control knows how to deal with it itself.'
Read the details on https://web.archive.org/web/20101229015404/http://msdn.microsoft.com/en-us/library/eeah46xd(v=vs.80).aspx .
I just had the same problem, and as you can see from the link Roel provided, the original poster DID have the correct signature.
Turns out this is a bug in MFC itself. Find ON_WM_CTLCOLOR_REFLECT in afxmsg_.h and you'll notice that CtlColor is missing the "&" before it. I guess the older compilers didn't mind. Add the "&" to make it "&CtlColor" and the error is fixed.
Alternatively, if you don't like changing the official headers, you could #under ON_WM_CTLCOLOR_REFLECT in your own code and define it again properly.
I notice many other (maybe all?) reflected messages in that file have the same problem too.
I have been tasked with migrating our product's UI to VS2010. It is an MFC app, originally written in VC6. I have performed the following steps:
Converted the VC6 .dsp using VS2010
fixed up compile errors due to stricter VS2010 compiler
Removed all project references to VC6 mfc libs and directories
My problem is that for a dialog object (actually it's a CPropertyPage object), OnInitDialog() is not being called before other methods are. This causes an exception as OnInitDialog() needs to setup member variables.
The dialog class (CPAGEViewDefRecordFields) is subclassed from our own CValidatedPropertyPage, which in turn is derived from the MFC CPropertyPage class. The virtual method OnInitDialog() is present in all subclasses.
In the VS2010 version, when DoModal() is called on the containing property sheet, the OnInitDialog() method of the CPAGEViewDefRecordFields class is not being called. In the VC6 version, it is being called and all works ok.
In VC6, I can see that the message WM_INITDIALOG is sent, and handled in AfxDlgProc(), which in turn then calls OnInitDialog() of the dialog object.
In the VS2010 version, the first message that is processed is WM_NOTIFY, not WM_INITDIALOG.
Unfortunately I have no prior experience in MFC. What I am assuming that something has changed in the behaviour of MFC between the VC6 version and the VS2010 version. However I've not been able to find anything on the net which is similar to this.
Is there another migration step I have missed? Should I have to do something to the resources in the project when doing the migration?
I have checked that the resource is tied to the correct cpp file, as I can double click on the property page, and the IDE takes me to the correct file for the CPAGEViewDefRecordFields class.
If any of you have any ideas, I'd be very grateful.
Thanks!
Chris.
class CPAGEViewDefRecordFields : public CValidatedPropertyPage
{
public:
// Construction
CPAGEViewDefRecordFields(CWnd* pParent,
CXpViewProp* pViewProp,
CFont* pFont = NULL,
UINT nIDCaption = 0,
BOOL bSumOpRequired = TRUE,
BOOL bMinMaxRequired = TRUE,
BOOL bAllRecords = TRUE,
BOOL bShowInitSel = TRUE,
XLong lLimits = 0,
BOOL bSortSelTree = TRUE,
CXpThreshBaseLogProp* pThreshLogProp = NULL);
~CPAGEViewDefRecordFields();
// Dialog Data
//{{AFX_DATA(CPAGEViewDefRecordFields)
enum { IDD = IDD_VIEW_DEF_RECORD_FIELDS };
//}}AFX_DATA
// Overrides
// ClassWizard generate virtual function overrides
//{{AFX_VIRTUAL(CPAGEViewDefRecordFields)
virtual BOOL OnInitDialog();
//}}AFX_VIRTUAL
virtual BOOL OnSetActive();
virtual BOOL OnKillActive();
virtual void OnOK();
protected:
...
// Generated message map functions
//{{AFX_MSG(CPAGEViewDefRecordFields)
afx_msg void OnPbRemove();
afx_msg void OnPbAdd();
afx_msg void OnDblclkAvailableFields(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDblclkSelectedFields(NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
...
UPDATE:
After some debugging, I can see what I think is the problem. However, not being an MFC programmer, I don't understand it.
I can see that OnInitDialog() is being called for the property sheet, and that a WM_INITDIALOG is then sent from the property sheet to the property pages. however, at some point in the windows internals, a WM_NOTIFY message is being sent, so this is the first message that is received, not the expected WM_INITDIALOG
I've highlighted the points on the stack trace, attached - can anyone explain why this is occuring? Is this normal behaviour - should I be catering for this in the future?
I've actually found a workaround, and that's to have an initialised flag, so that no code is executed until OnInitDialog() has been called. This is not the best solution, and I fear is more of a hack, so i would still appreciated any understanding of these messages. (I'm not an MFC programmer by trade you see!)
thanks!
OnInitDialog is called after all the dialog controls are created and just before the dialog box is displayed.
Thought I'd better answer this.
The answer came from a SO user's comment:
Your workaround with an initialized flag is the same as I would do. It looks like a tree view sends a notification when the tree view is created but your dialog isn't ready yet. You might not know when other controls do the same thing, so you need an initialized flag
The "workaround" is the only way to guarantee that the dialog is ready.