I want to change the font size of calender control in Win7 to make it touch screen compatible. The theme in my machine is Aero. CalendarFont property does not have any effect on the Aero theme.
So I have overrided OnDropDown method to disable theme for the calander control. Now the font has changed, but the calender window size is not changed. The following image shows the window I am seeing
The code is given below. What should I do to increase the size of the calender window?
protected override void OnDropDown(EventArgs e)
{
IntPtr pointerToCalenderWindow = SendMessage(Handle, DtmGetmonthcal,0,0);
// Disble Theme
SetWindowTheme(pointerToCalenderWindow, "", "");
var rect = new Rectangle();
SendMessage(pointerToCalenderWindow, McmGetminreqrect, 0, ref rect);
MoveWindow(pointerToCalenderWindow,0,0,rect.Right + 2, rect.Bottom + 2, true);
base.OnDropDown(e);
}
private const int McmFirst = 0x1000;
private const int McmGetminreqrect = (McmFirst + 9);
private const int McsWeeknumbers = 0x4;
private const int DtmFirst = 0x1000;
private const int DtmGetmonthcal = (DtmFirst + 8);
private const int WMPAINT = 0x000F;
[DllImport("uxtheme.dll")]
private static extern int SetWindowTheme(IntPtr hWnd, string appname, string idlist);
[DllImport("User32.dll")]
private static extern IntPtr SendMessage(IntPtr h,
int msg,
int param,
int data);
[DllImport("User32.dll")]
private static extern int MoveWindow(IntPtr h,
int x,
int y,
int width,
int height,
bool repaint);
It seems that this question is about the same problem as yours:
The answer states that there are actually two windows used for the calendar part (an 'inner' and an 'outer' one) and that you need to set the size for the outer window correctly.
Related
This question already has answers here:
RichTextBox syntax highlighting in real time--Disabling the repaint
(3 answers)
Closed 2 years ago.
I'm doing a text editor based on RichTextBox. It has to handle complex formatting (BIU, colored text, etc). The problem is that all formatting tools are selection based, e.g. i have to select piece of text, format it, select next, etc.
it takes time, and it is visible for user.
is there a way to turn-off RichTextBox redraw, then do formatting, then turn-on redraw?
Or maybe any other way to handel complex formatting quickly?
Decision found and it's working.
Wrote a wrap-class using this code
Class itself:
public class RichTextBoxRedrawHandler
{
RichTextBox rtb;
public RichTextBoxRedrawHandler (RichTextBox _rtb)
{
rtb = _rtb;
}
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, int wParam, ref Point lParam);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, int wParam, IntPtr lParam);
const int WM_USER = 1024;
const int WM_SETREDRAW = 11;
const int EM_GETEVENTMASK = WM_USER + 59;
const int EM_SETEVENTMASK = WM_USER + 69;
const int EM_GETSCROLLPOS = WM_USER + 221;
const int EM_SETSCROLLPOS = WM_USER + 222;
private Point _ScrollPoint;
private bool _Painting = true;
private IntPtr _EventMask;
private int _SuspendIndex = 0;
private int _SuspendLength = 0;
public void SuspendPainting()
{
if (_Painting)
{
_SuspendIndex = rtb.SelectionStart;
_SuspendLength = rtb.SelectionLength;
SendMessage(rtb.Handle, EM_GETSCROLLPOS, 0, ref _ScrollPoint);
SendMessage(rtb.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
_EventMask = SendMessage(rtb.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
_Painting = false;
}
}
public void ResumePainting()
{
if (!_Painting)
{
rtb.Select(_SuspendIndex, _SuspendLength);
SendMessage(rtb.Handle, EM_SETSCROLLPOS, 0, ref _ScrollPoint);
SendMessage(rtb.Handle, EM_SETEVENTMASK, 0, _EventMask);
SendMessage(rtb.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
_Painting = true;
rtb.Invalidate();
}
}
}
Usage:
RichTextBoxRedrawHandler rh = new RichTextBoxRedrawHandler(richTextBoxActually);
rh.SuspendPainting();
// do things with richTextBox
rh.ResumePainting();
My initial approach to this was using GetSystemMetrics with SystemMetric.SM_CXSIZE and some simple math based on which buttons are available (times 3, or times 1), via WindowStyle.
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(SystemMetric smIndex);
This has an issue on Windows 10, where the calculated width is approximately 70% of actual. So the width covers just two buttons - maximize and close. Windows 7 and 8.1 are fine, same DPI setting, where it covers all buttons.
I checked a few existing questions on Stack Overflow, and had most success with this one from 2011:
How do I compute the non-client window size in WPF?
Unfortunately, while the suggested approach does work in windows 8.1, it calculates 0 on Windows 10 (latest version, all recommended updates). Is there a way that works on all OS from 7 to 10?
Code was taken from the above answer and modified to calculate total width of window's control buttons, by window handle (hwnd), and changed marshalling to RECT from Rectangle (then I get correct values of left/right).
public static int GetControlButtonsWidth(IntPtr hwnd)
{
// Create and initialize the structure
TITLEBARINFOEX tbi = new TITLEBARINFOEX();
tbi.cbSize = Marshal.SizeOf(typeof(TITLEBARINFOEX));
// Send the WM_GETTITLEBARINFOEX message
SendMessage(hwnd, WM_GETTITLEBARINFOEX, IntPtr.Zero, ref tbi);
int sum = tbi.rgrect.Sum(r => r.right - r.left);
// Return the filled-in structure
return sum;
}
internal const int WM_GETTITLEBARINFOEX = 0x033F;
internal const int CCHILDREN_TITLEBAR = 5;
[StructLayout(LayoutKind.Sequential)]
internal struct TITLEBARINFOEX
{
public int cbSize;
public RECT rcTitleBar;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public int[] rgstate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public RECT[] rgrect;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(
IntPtr hWnd,
int uMsg,
IntPtr wParam,
ref TITLEBARINFOEX lParam);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left, top, right, bottom;
}
You can use DwmGetWindowAttribute, the combined width for those 3 buttons should be 185 pixels on Windows 10, at 125% DPI. Note that if your application is not DPI aware, then the result will still be the same, 185 for example.
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute(
IntPtr hwnd, int attr, out RECT ptr, int size);
public void foo()
{
int DWMWA_CAPTION_BUTTON_BOUNDS = 5;
RECT rc;
if (0 != DwmGetWindowAttribute(this.Handle, DWMWA_CAPTION_BUTTON_BOUNDS,
out rc, Marshal.SizeOf(typeof(RECT))))
{
//error
}
int width = rc.right - rc.left;
}
I'm trying to figure out how this code works but I just can not figure out what makes it click through.
Yes, this code is not mine since i'm trying to learn/understand it.
Assume I want the tranparancy but not the click through what needs to be changed and why?
I have been over the Windows styles pages over and over and still can not get my head around the click through part.
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class TransparentWindow : MonoBehaviour
{
[SerializeField]
private Material m_Material;
private struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
[DllImport("user32.dll")]
private static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll")]
static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
static extern int SetLayeredWindowAttributes(IntPtr hwnd, int crKey, byte bAlpha, int dwFlags);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern int SetWindowPos(IntPtr hwnd, int hwndInsertAfter, int x, int y, int cx, int cy, int uFlags);
[DllImport("Dwmapi.dll")]
private static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margins);
const int GWL_STYLE = -16;
const uint WS_POPUP = 0x80000000;
const uint WS_VISIBLE = 0x10000000;
const int HWND_TOPMOST = -1;
void Start()
{
#if !UNITY_EDITOR // You really don't want to enable this in the editor..
int fWidth = Screen.width;
int fHeight = Screen.height;
var margins = new MARGINS() { cxLeftWidth = -1 };
var hwnd = GetActiveWindow();
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
// Transparent windows with click through
SetWindowLong(hwnd, -20, 524288 | 32);//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
SetLayeredWindowAttributes(hwnd, 0, 255, 2);// Transparency=51=20%, LWA_ALPHA=2
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
DwmExtendFrameIntoClientArea(hwnd, ref margins);
#endif
}
void OnRenderImage(RenderTexture from, RenderTexture to)
{
Graphics.Blit(from, to, m_Material);
}
}
This function:
SetWindowLong(hwnd, -20, 524288 | 32);
does the trick. Windows implements the rule that Mircosoft made which is that a window that is transparent to the user must be transparent to the mouse.
With the transparency bit set WS_EX_TRANSPARENT the window becomes transparent to mouse too and click passes to the painted layer behind the transparent window.
You need not understand but make use of this 'OS feature' which was probably implemented to cover for something else.
Read this article about the subject and this answer that explains the parameters
I have created a class change the appearance of the calander.
The class is based on these previous stackoverflow questions:
Source1: Setting calendar size when overriding DateTimePicker to add week numbers
Source2: Increase Font Size of DateTimePicker Calender in Win7 Aero Theme
This is the class:
class DateTimePickerImpl : DateTimePicker
{
private const int McmFirst = 0x1000;
private const int McmGetminreqrect = (McmFirst + 9);
private const int McsWeeknumbers = 0x4;
private const int DtmFirst = 0x1000;
private const int DtmGetmonthcal = (DtmFirst + 8);
[DllImport("User32.dll")]
private static extern int GetWindowLong(IntPtr handleToWindow, int offsetToValueToGet);
[DllImport("User32.dll")]
private static extern int SetWindowLong(IntPtr h, int index, int value);
[DllImport("uxtheme.dll")]
private static extern int SetWindowTheme(IntPtr hWnd, string appname, string idlist);
[DllImport("User32.dll")]
private static extern IntPtr SendMessage(IntPtr h, int msg, int param, int data);
[DllImport("User32.dll")]
private static extern IntPtr GetParent(IntPtr h);
[DllImport("User32.dll")]
private static extern int SendMessage(IntPtr h, int msg, int param, ref Rectangle data);
[DllImport("User32.dll")]
private static extern int MoveWindow(IntPtr h, int x, int y, int width, int height, bool repaint);
protected override void OnDropDown(EventArgs e)
{
CalendarFont = new Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
const int offsetToGetWindowsStyles = (-16);
IntPtr pointerToCalenderWindow = SendMessage(Handle, DtmGetmonthcal, 0, 0);
SetWindowTheme(pointerToCalenderWindow, "", "");
int styleForWindow = GetWindowLong(pointerToCalenderWindow, offsetToGetWindowsStyles);
styleForWindow = styleForWindow | McsWeeknumbers;
Rectangle rect = new Rectangle();
SendMessage(pointerToCalenderWindow, McmGetminreqrect, 0, ref rect);
rect.Width = rect.Width + 30;
rect.Height = rect.Height + 10;
SetWindowLong(pointerToCalenderWindow, offsetToGetWindowsStyles, styleForWindow);
MoveWindow(pointerToCalenderWindow, 0, 0, rect.Width, rect.Height, true);
IntPtr parentWindow = GetParent(pointerToCalenderWindow);
MoveWindow(parentWindow, 0, 0, rect.Width, rect.Height, true);
base.OnDropDown(e);
}
}
Afther implementing this class the visible text of the datetimepicker changes to whatever you choose. But when using dateTimePickerImpl.Value it always returns the it began with (the time the datetimpicker loaded). I already found out by adding a method to the ValueChanged event that this event never happens. I found some similar problems online but these were all solved by setting the checked property of the datetimepicker to true. In my case the checked property is already true.
What did i do to break the datetimepicker?
I had to create the datetime picker manually instead of dragging it from the toolbox into the designer.
DateTimePickerImpl dtp = new DateTimePickerImpl();
dtp.Location = new Point(3, 254);
dtp.Name = "dtp";
dtp.Size = new Size(271, 26);
dtp.TabIndex = 25;
panel1.Controls.Add(dtp);
i need to open a word document in a panel control of Windows Forms Application to view/edit file and save.
i use this statement :
[DllImport("user32.dll")]
public static extern int FindWindow(string strclassName, string strWindowName);
[DllImport("user32.dll")]
static extern int SetParent(int hWndChild, int hWndNewParent);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
int hWnd, // handle to window
int hWndInsertAfter, // placement-order handle
int X, // horizontal position
int Y, // vertical position
int cx, // width
int cy, // height
uint uFlags // window-positioning options
);
[DllImport("user32.dll", EntryPoint = "MoveWindow")]
static extern bool MoveWindow(
int hWnd,
int X,
int Y,
int nWidth,
int nHeight,
bool bRepaint
);
const int SWP_DRAWFRAME = 0x20;
const int SWP_NOMOVE = 0x2;
const int SWP_NOSIZE = 0x1;
const int SWP_NOZORDER = 0x4;
const int SWP_FRAMECHANGED = 0x20;
ToolsComponents.MSWord word = new ToolsComponents.MSWord();
private void toolStripButton2_Click(object sender, EventArgs e)
{
word.CreateWordDocument();
word.OpenFile(#"C:\Users\ME\Documents\test.docx", true);
int wordWnd = FindWindow("Opusapp", null);
if (wordWnd != 0)
{
int ret = SetParent(wordWnd, pnlShowForm.Handle.ToInt32());
//int ret2 = FindWindow("Opusapp", null);
//ret = SetParent(wordWnd, pnlShowForm.Handle.ToInt32());
SetWindowPos(wordWnd, pnlShowForm.Handle.ToInt32(), 0, 0, pnlShowForm.Bounds.Width - 20, pnlShowForm.Bounds.Height - 20, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME);
MoveWindow(wordWnd, -5, -33, pnlShowForm.Bounds.Width + 10, pnlShowForm.Bounds.Height + 57, true);
}
}
private void frmDocumentManager_FormClosing(object sender, FormClosingEventArgs e)
{
if (word != null)
{
word.CloseDoc(true);
word.Quit();
}
but this is not a good solution and have problem in runtime.
in sometimes MS word and document started outside the form and i can't control this.