How to prevent WTL CSplitterWindow resize? - c++

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;

Related

MFC MDI Problem with SetLook even with header file in place

I've implemented a Property Sheet and several Property Pages that are called from the Main Menu from the MainFrame.cpp spawned from my issue here:
MFC MDI Designing user preferences dialog GUI layout functionality
The code I landed on was:
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx)
Other messages...
ON_COMMAND(ID_SETTINGS_DIALOG, OnSettingsTools)
Other messages...
END_MESSAGE_MAP()
void CMainFrame::OnSettingsTools()
{
SettingsSheet SettingsSheet(L"Application Settings");
CSettingsPowerUser m_PowerUser;
CSettingsReset m_Reset;
CSettingsToolbars m_Toolbars;
CSettingsUserWarnings m_UserWarnings;
SettingsSheet.AddPage(&m_PowerUser);
SettingsSheet.AddPage(&m_Reset);
SettingsSheet.AddPage(&m_Toolbars);
SettingsSheet.AddPage(&m_UserWarnings);
//SetLook(CMFCPropertySheet::PropSheetLook_OneNoteTabs);
SettingsSheet.DoModal();
}
Yielding:
I have included in MainFrame.h
#include <afxpropertysheet.h>
The property sheet is using CMFCPropertySheet in both the .cpp & .h as shown here in its .h file:
class SettingsSheet : public CMFCPropertySheet
{
DECLARE_DYNAMIC(SettingsSheet)
public:
SettingsSheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0);
SettingsSheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0);
virtual ~SettingsSheet();
protected:
DECLARE_MESSAGE_MAP()
};
So what the issue here is, you can see that I had to comment out the SetLook(CMFCPropertySheet::PropSheetLook_OneNoteTabs); because I get an error that says SetLook identifier not found C3861.
If I hover inside the MainForm.h and right click the #include <afxpropertysheet.h> the file opens right up in the IDE and if I search for SetLook it most certainly can find it in the public section of the function.
So I've seen multiple code examples that use that SetLook and one of the tutorials I looked at used it and it works fine as I'm using VS2017.
I realize what a "not found is", but I'm at a loss as to why it's a problem here. It is the only error I am having now and I would like to use that functionality.
Thoughts on what may be going on here?
Update:
Following Dxiv's advice I changed the code to:
SettingsSheet.SetLook(CMFCPropertySheet::PropSheetLook_OneNoteTabs);
It now compiles and runs, but have some odd results, it only shows one property page, and all the rest are AWOL.
I have figured out what the issue was; when I created the dialogs I used the base class of:
CPropertyPage
instead of:
CMFCPropertyPage
I had set the sheet to:
CMFCPropertySheet
and assumed it carried down since it compiled and displayed the tab view correctly, but failed on the other SetLook property options.
Once I adjusted all the dialogs to CMFCPropertyPage, the SetLook started working immediately. So I consider this issue CLOSED.

DirectXTK no member in "Mouse" for "SetWindow(HWND hwnd)"

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>

How to get ribbon control in MFC feature pack to process ID_WINDOW_TILE_VERT

I'm porting an older MFC application to use MFC feature pack with ribbon UI and have found the ribbon UI doesn't process MDI windows tiling commands such ID_WINDOW_TILE_VERT. Is there a way to enable this functionality?
Single stepping through the MFC source I get as far as the following in C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc\winmdi.cpp, which seems correct;
BOOL CMDIFrameWnd::OnMDIWindowCmd(UINT nID)
{
ASSERT(m_hWndMDIClient != NULL);
UINT msg;
UINT wParam = 0;
switch (nID)
{
default:
return FALSE; // not for us
case ID_WINDOW_ARRANGE:
msg = WM_MDIICONARRANGE;
break;
case ID_WINDOW_CASCADE:
msg = WM_MDICASCADE;
break;
case ID_WINDOW_TILE_HORZ:
wParam = MDITILE_HORIZONTAL;
// fall through
case ID_WINDOW_TILE_VERT:
ASSERT(MDITILE_VERTICAL == 0);
msg = WM_MDITILE;
break;
}
::SendMessage(m_hWndMDIClient, msg, wParam, 0);
return TRUE;
}
I have also tried calling
MDITile(MDITILE_HORIZONTAL);
directly, which essentially does the same thing and does not work.
From some experimentation, when the MFC mdi interface is based on CMDIFrameWndEx frames hosting dockable panes based CMDIChildWndEx and tabbed documents are enabled, floating windows are not available and hence neither are tiling or cascading.
To enable tiling, simply remove the line
EnableMDITabbedGroups(TRUE, mdiTabParams);
from your CMainFrame::OnCreate method. The downside is you also lose your nice tabbed document UI. FWIW, I also tried calling EnableDocking(CBRS_FLOAT_MULTI) after enabling tabbed groups, but it does not make any difference. Also under discussion here
Update: In order to keep the tabbed interface and split the screens, the following alternative works well to split a single horizontal view with multiple tabs into two views, with current tab in the new view.
void SplitViews(CMDIFrameWndEx *pFrame)
{
pFrame->MDITabNewGroup();
pFrame->MDITabMoveToNextGroup();
}

C++ Winapi HWND Get element by Name

Is there a way I can get a HWND by it's property "name"? I know that every IDE has its own properties for HWND elements but those properties are applied to the HWND.
I'm not working in Visual Studio, this is just a case. I want to get HWNDs by Name in C++ without VS Libraries.
For example:
HWND button = GetHwndByName("button1"); //Example
Property "name" is button1
I'm going to assume you're either trying to access your GUI controls in code or some other program's GUI controls.
As some people have mentioned, the (name) property in the properties editor is just the variable name used for that control. Your screenshot shows Visual Studio editing a .net program. In the case of .net, the (name) field is the name of the class member of the window class that represents the control. So if (name) is button1 then Visual Studio might generate code like
// pseudo-C++/C#-like
class Form1 : public System.Windows.Forms.Form {
private:
System.Windows.Forms.Button *button1;
...
};
The idea here is that you would have event handlers as part of your Form1 class:
void Form1::onButton1Clicked(void)
{
this->button1->SetText("You clicked me!");
}
As such, the (name) is not an intrinsic property of the window from Windows's point of view.
I don't know what CA Plex's GUI editor looks like, but I would assume, given you said you were using C++, that it either
a) produces a class like the one I pasted above, in which case you would just use the (name) directly as members, or
b) produces a header file with each of those control names as global HWND variables
Either way, you can just use them directly from within your code. Perhaps have something like
void doToAllButtons(void (*f)(HWND, LPARAM), LPARAM lParam)
{
(*f)(button1, lParam);
(*f)(button2, lParam);
(*f)(button3, lParam);
}
and simply write an appropriate function to call via this one.
If you need to interface with another program and want to use its variable names, then you're out of luck. You'll need to find the windows you want some other way, such as with FindWindow().

Extend default windows title bar [duplicate]

I've seen that some apps (maybe not .NET apps) that have an extra button on the left from the minimize button on the form's title bar? How can I achieve this in C#?
UPDATE: Added a solution that will work with Aero enabled for Windows Vista and Windows 7
***Non-Aero Solution***
The non-client area of a window interaction is managed by a series of non-client specfic messages. For example WM_NCPAINT message is sent to the window procedure to paint the non-client area.
I have never done this from .NET, but I suspect you can overide the WndProc and handle the WM_NC* messages to achieve what you want.
Update: Since I never tried this from .NET I got a few minutes and thought I would give it a quick try.
Trying this on Windows 7, I found that I needed to disable the Themes for the Window if I wanted to OS to do the base rendering of the non-client area. So here is a short test. I used GetWindowDC to get the DC of the entire window rather than GetDCEx, that was just because I could interop that from memory and did not have lookup all the flag constants for GetDcEx. And of course the code could do with more error checking.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class CustomBorderForm : Form
{
const int WM_NCPAINT = 0x85;
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("user32.dll", SetLastError = true)]
public static extern void DisableProcessWindowsGhosting();
[DllImport("UxTheme.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr SetWindowTheme(IntPtr hwnd, string pszSubAppName, string pszSubIdList);
public CustomBorderForm()
{
// This could be called from main.
DisableProcessWindowsGhosting();
InitializeComponent();
}
protected override void OnHandleCreated(EventArgs e)
{
SetWindowTheme(this.Handle, "", "");
base.OnHandleCreated(e);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_NCPAINT:
{
IntPtr hdc = GetWindowDC(m.HWnd);
using (Graphics g = Graphics.FromHdc(hdc))
{
g.FillEllipse(Brushes.Red, new Rectangle((Width-20)/2, 8, 20, 20));
}
ReleaseDC(m.HWnd, hdc);
}
break;
}
}
}
}
Btw. I called DisableProcessWindowsGhosting, this will stop the OS from drawing the non-client area if the application takes too long to respond to windows messages. If you do not do this, then in some situations the border will be renderd but your adornments will not be shown. So that depends on your requirements it that is right for you or not.
***Aero supported solution***
Prompted by the comment from #TheCodeKing, I thought I would take another look at this. It turns out this can be done in a fully documented way while supporting Aero. But it is not for the faint of heart. I will not provide a complete solution here, there are still some kinks to workout, but it does the basics.
This code/solution is based off the Win32 example which can be found at the following location
http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx
In principal what you need to do is the following.
Extend the client area of the window to cover the Frame. This is done by handling the WM_NCCALCSIZE message and returning 0. This gives the Non-Client area a size of 0 and therefore the client area now covers the entire window.
Extend the Frame into the client area using DwmExtendFrameIntoClientArea. This gets the OS to render the Frame over the client area.
The above steps will give you a windows with the standard glass frame excluding the system menu (Window Icon) and the title. The minimize, maximize and close buttons will still be drawn and will work. What you will not be able to do is drag or resize the window, this is because the frame is not really there, remember the client area covers the whole window, we have just asked the OS to draw the frame onto the client area.
Now you can draw on the window as normal, even on top of the frame. You can even put controls in the caption area.
Finally, allow the DWM to handle hit-testing for you, by calling DwmDefWindowProc from your WndProc (before you've processed it). It returns a boolean indicating whether the DWM handled the message for you.
Simple Solution:
Step 1: Create a Windows Form (this will be your custom title bar)
-Set Form Border Style to None
-Add whatever controls you would like to this
-I will name this custom form "TitleBarButtons"
Step 2. In the from that you want to use this custom control in add
titleBarBtn = new TitleBarButtons();
titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5);
titleBarBtn.Show();
titleBarBtn.Owner = this;
To your constructor... you can mess with the offsets this just fit in a nice position for my app
Step 3. Add the move event to your main form
private void Form14_Move(object sender, EventArgs e)
{
titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5);
}
Please let me know if you would like a better explanation of any of the above code.
I think a way to do this would be to handle WM_NCPAINT message (non-client paint) to draw the button, and to handle non-client mouse clicks to know someone clicked on the "button".