I am developing an application that controls an Machine.
When I receive an error from the Machine the users should be able to directly notice it, one way that is done is Flashing the tray on the taskbar. When the machine clears the error the tray should stop flashing.
There's one little annoyance using the FlashWindowEx function, when I clear the flashing of the window, it stays (in my case WinXP) orange (not flashing).
[Flags]
public enum FlashMode {
/// <summary>
/// Stop flashing. The system restores the window to its original state.
/// </summary>
FLASHW_STOP = 0,
/// <summary>
/// Flash the window caption.
/// </summary>
FLASHW_CAPTION = 1,
/// <summary>
/// Flash the taskbar button.
/// </summary>
FLASHW_TRAY = 2,
/// <summary>
/// Flash both the window caption and taskbar button.
/// This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
/// </summary>
FLASHW_ALL = 3,
/// <summary>
/// Flash continuously, until the FLASHW_STOP flag is set.
/// </summary>
FLASHW_TIMER = 4,
/// <summary>
/// Flash continuously until the window comes to the foreground.
/// </summary>
FLASHW_TIMERNOFG = 12
}
public static bool FlashWindowEx(IntPtr hWnd, FlashMode fm) {
FLASHWINFO fInfo = new FLASHWINFO();
fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
fInfo.hwnd = hWnd;
fInfo.dwFlags = (UInt32)fm;
fInfo.uCount = UInt32.MaxValue;
fInfo.dwTimeout = 0;
return FlashWindowEx(ref fInfo);
}
[StructLayout(LayoutKind.Sequential)]
public struct FLASHWINFO {
public UInt32 cbSize;
public IntPtr hwnd;
public UInt32 dwFlags;
public UInt32 uCount;
public UInt32 dwTimeout;
}
In my case I use FLASHW_TRAY to start flashing and FLASHW_STOP to stop the flashing.
Am I doing something wrong or is this a known bug of WinXP and is there a fix for it?
Behaviour is the same when a window finishes flashing for as long as it's supposed to: the taskbar button stays coloured. I don't think this is a bug. If you think about it, when you use FLASHW_STOP, the flashing does in fact stop, but the point of the flashing is to get the user's attention. The button stays coloured because the user still may not have looked down and discovered which window was trying to get her attention. Keeping the button coloured keeps that information available.
Here's an error:
fInfo.uCount = UInt32.MaxValue;
You should set fInfo.uCount to zero when calling with FLASHW_STOP parameter.
Otherwise when you try to call stop when taskbar button is active it will stay active.
You can check a note about undefined behavior here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms679348(v=vs.85).aspx
I know that's an old post but it can help other people to solve this problem fast.
If that's the expected functionality I think it's not so useful, at least there should be a reset.
I fixed it now just using the FLASHW_ALL | FLASHW_TIMERNOFG combination.
Just set uCount to 0 to stop the flashing.
fixed with uCount=0
if (flags = FLASHW_STOP) { .uCount = 0 } else { .uCount = 800 }
The misbehaviour is that if you are calling flashw_stop from a click/kb event from inside the Window itself, the taskbar button stay colored if a that moment was colored.
With that new logic line, done.
Related
I hook a window into a Panel using this code:
SetParent(win, pnlApp.Handle);
SetWindowLong(win, GWL_STYLE, WS_VISIBLE);
MoveWindow(win, 0, 0, pnlApp.Width, pnlApp.Height, true);
where win is the Window handle, as an IntPtr. Here think about Notepad, it will hook very well into a Panel.
But when I try to release (unhook) it using this code:
SetParent(win, (IntPtr)0);
It's shown without the Window frame! I mean it will release into the Desktop again, but it has not any Window frame.
How to solve this issue?
In relation to the code in the question:
SetWindowLong() should be replaced by SetWindowLongPtr() - see the warning in the Docs. The latter calls the former in case the calling code requires it.
You need to call GetWindowLongPtr() to get the current Window Styles, then add or remove Styles as needed; store the original value: it will be used to restore the previous state.
► In the example, the WS_SYSMENU Style is removed, hence the Window will not show the System Menu and all the Buttons usually located in the Caption. It's just an example, to see how this works (it may not be effective with all Windows).
SetParent() returns the Handle of the previous Parent. Store this value, it will be needed to restore the Window to its previous owner, whatever that is. If the Window is a top-level Window, the previous Parent appears to be the Desktop, so you expect IntPtr.Zero. It might not be, you can get a Handle that is not IntPtr.Zero. Just store the returned value, see what that is, if you're interested :)
You should check the return value of both GetWindowLongPtr() and SetWindowLongPtr(): if it's 0, then there was an error. You can use Marshal.GetLastWin32Error() to get the error code. Note that SetWindowLongPtr() doesn't clear the error code, so you have to clear it yourself, calling SetLastError(0).
You can use MoveWindow() to reposition the Windows inside the new Parent's bounds; I suggest to call SetWindowPos() instead, you have more options. See the code here.
Disclaimer: keep in mind what's in Raymond Chen's blog post:
Is it legal to have a cross-process parent/child or owner/owned window relationship
In other words, it's a just because you asked thing :)
Set these Fields (or whatever fits):
windowdHwnd is the Handle of the Window to re-parent
oldParent is the Handle of the previous Parent, returned by SetParent()
oldStyles will store the previous Window's Styles, returned by GetWWindowLongPtr()
IntPtr windowdHwnd = IntPtr.Zero;
IntPtr oldParent = (IntPtr)(-1);
int oldStyles = 0;
// [...]
When you have the Handle of the Window you care about, set windowdHwnd to this value. Call this code after (it could be a method, pass the Window Handle and the Container Control that will be the new Parent - here, a Control named somePanel).
// Already parented, resets the previous styles, clean up and return
if (windowdHwnd != IntPtr.Zero && oldParent != (IntPtr)(-1)) {
NativeMethods.SetParent(windowdHwnd, oldParent);
NativeMethods.SetWindowLongPtr(windowdHwnd, NativeMethods.GWL_Flags.GWL_STYLE, new IntPtr(oldStyles));
windowdHwnd = IntPtr.Zero;
oldParent = (IntPtr)(-1);
return;
}
// Store the existing Styles, to restore when the Window is dismissed
oldStyles = NativeMethods.GetWindowLongPtr(windowdHwnd, NativeMethods.GWL_Flags.GWL_STYLE);
if (oldStyles == IntPtr.Zero) {
int error = Marshal.GetLastWin32Error(); // Show the error code or throw an exception
return;
}
// Removes the System Menu from the Window: it will also remove the Buttons from the Caption
int newStyle = oldStyles.ToInt32()^ (int)NativeMethods.WinStyles.WS_SYSMENU;
NativeMethods.SetLastError(0);
// Sets the new Styles
IntPtr result = NativeMethods.SetWindowLongPtr(windowdHwnd, NativeMethods.GWL_Flags.GWL_STYLE, (IntPtr)newStyle);
if (result == IntPtr.Zero) {
int error = Marshal.GetLastWin32Error(); // Show the error code or throw an exception
return;
}
oldParent = NativeMethods.SetParent(windowdHwnd, somePanel.Handle);
// Repositions the Window and shows it, if needed
var flags = NativeMethods.SWP_Flags.SWP_ASYNCWINDOWPOS | NativeMethods.SWP_Flags.SWP_SHOWWINDOW;
NativeMethods.SetWindowPos(windowdHwnd, IntPtr.Zero, 0, 0, somePanel.Width, somePanel.Height, flags);
You can write (this just removes):
int newStyle = oldStyles &~(int)NativeMethods.WinStyles.WS_SYSMENU;
instead of (this switches on/off):
int newStyle = oldStyles ^ (int)NativeMethods.WinStyles.WS_SYSMENU;
NativeMethods class:
using System.Runtime.InteropServices;
public class NativeMethods
{
[Flags]
public enum SWP_Flags : uint
{
/// <summary>Retains the current size (ignores the cx and cy parameters).</summary>
SWP_NOSIZE = 0x0001,
/// <summary>Retains the current position (ignores X and Y parameters).</summary>
SWP_NOMOVE = 0x0002,
/// <summary>Retains the current Z order (ignores the hWndInsertAfter parameter).</summary>
SWP_NOZORDER = 0x0004,
/// <summary>Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to
/// the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent
/// window uncovered as a result of the window being moved. When this flag is set, the application must
/// explicitly invalidate or redraw any parts of the window and parent window that need redrawing.</summary>
SWP_NOREDRAW = 0x0008,
/// <summary>Does not activate the window. If this flag is not set, the window is activated and moved to the
/// top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter
/// parameter).</summary>
SWP_NOACTIVATE = 0x0010,
/// <summary>Draws a frame (defined in the window's class description) around the window.</summary>
SWP_DRAWFRAME = 0x0020,
/// <summary>Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to
/// the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE
/// is sent only when the window's size is being changed.</summary>
SWP_FRAMECHANGED = 0x0020,
/// <summary>Displays the window.</summary>
SWP_SHOWWINDOW = 0x0040,
/// <summary>Hides the window.</summary>
SWP_HIDEWINDOW = 0x0080,
/// <summary>Discards the entire contents of the client area. If this flag is not specified, the valid
/// contents of the client area are saved and copied back into the client area after the window is sized or
/// repositioned.</summary>
SWP_NOCOPYBITS = 0x0100,
/// <summary>Does not change the owner window's position in the Z order.</summary>
SWP_NOOWNERZORDER = 0x0200,
/// <summary>Same as the SWP_NOOWNERZORDER flag.</summary>
SWP_NOREPOSITION = 0x0200,
/// <summary>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</summary>
SWP_NOSENDCHANGING = 0x0400,
/// <summary>Internal use.</summary>
SWP_NOCLIENTSIZE = 0x0800,
/// <summary>Internal use.</summary>
SWP_NOCLIENTMOVE = 0x1000,
/// <summary>Prevents generation of the WM_SYNCPAINT message.</summary>
SWP_DEFERERASE = 0x2000,
/// <summary>If the calling thread and the thread that owns the window are attached to different input queues,
/// the system posts the request to the thread that owns the window. This prevents the calling thread from
/// blocking its execution while other threads process the request.</summary>
SWP_ASYNCWINDOWPOS = 0x4000
}
[Flags]
public enum WinStyles : uint
{
WS_BORDER = 0x00800000, //The window has a thin-line border.
WS_CAPTION = 0x00C00000, //The window has a title bar (includes the WS_BORDER style).
WS_CHILD = 0x40000000, //The window is a child window. A window with this style cannot have a menu bar. This style cannot be used with the WS_POPUP style.
WS_CHILDWINDOW = 0x40000000, //Same as the WS_CHILD style.
WS_CLIPCHILDREN = 0x02000000, //Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.
WS_CLIPSIBLINGS = 0x04000000, //Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighboring child window.
WS_DISABLED = 0x08000000, //The window is initially disabled. A disabled window cannot receive input from the user. To change this after a window has been created, use the EnableWindow function.
WS_DLGFRAME = 0x00400000, //The window has a border of a style typically used with dialog boxes. A window with this style cannot have a title bar.
WS_GROUP = 0x00020000, //The window is the first control of a group of controls. The group consists of this first control and all controls defined after it, up to the next control with the WS_GROUP style. The first control in each group usually has the WS_TABSTOP style so that the user can move from group to group. The user can subsequently change the keyboard focus from one control in the group to the next control in the group by using the direction keys.
//You can turn this style on and off to change dialog box navigation. To change this style after a window has been created, use the SetWindowLong function.
WS_HSCROLL = 0x00100000, //The window has a horizontal scroll bar.
WS_ICONIC = 0x20000000, //The window is initially minimized. Same as the WS_MINIMIZE style.
WS_MAXIMIZE = 0x01000000, //The window is initially maximized.
WS_MAXIMIZEBOX = 0x00010000, //The window has a maximize button. Cannot be combined with the WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified.
WS_MINIMIZE = 0x20000000, //The window is initially minimized. Same as the WS_ICONIC style.
WS_MINIMIZEBOX = 0x00020000, //The window has a minimize button. Cannot be combined with the WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified.
WS_OVERLAPPED = 0x00000000, //The window is an overlapped window. An overlapped window has a title bar and a border. Same as the WS_TILED style.
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | //The window is an overlapped window. Same as the WS_TILEDWINDOW style.
WS_CAPTION |
WS_SYSMENU |
WS_THICKFRAME |
WS_MINIMIZEBOX |
WS_MAXIMIZEBOX,
WS_POPUP = 0x80000000, //The windows is a pop-up window. This style cannot be used with the WS_CHILD style.
WS_POPUPWINDOW = WS_POPUP | //The window is a pop-up window. The WS_CAPTION and WS_POPUPWINDOW styles must be combined to make the window menu visible.
WS_BORDER |
WS_SYSMENU,
WS_SIZEBOX = 0x00040000, //The window has a sizing border. Same as the WS_THICKFRAME style.
WS_SYSMENU = 0x00080000, //The window has a window menu on its title bar. The WS_CAPTION style must also be specified.
WS_TABSTOP = 0x00010000, //The window is a control that can receive the keyboard focus when the user presses the TAB key. Pressing the TAB key changes the keyboard focus to the next control with the WS_TABSTOP style.
//You can turn this style on and off to change dialog box navigation. To change this style after a window has been created, use the SetWindowLong function. For user-created windows and modeless dialogs to work with tab stops, alter the message loop to call the IsDialogMessage function.
WS_THICKFRAME = 0x00040000, //The window has a sizing border. Same as the WS_SIZEBOX style.
WS_TILED = 0x00000000, //The window is an overlapped window. An overlapped window has a title bar and a border. Same as the WS_OVERLAPPED style.
WS_TILEDWINDOW = WS_OVERLAPPED | //The window is an overlapped window. Same as the WS_OVERLAPPEDWINDOW style.
WS_CAPTION |
WS_SYSMENU |
WS_THICKFRAME |
WS_MINIMIZEBOX |
WS_MAXIMIZEBOX,
WS_VISIBLE = 0x10000000, //The window is initially visible. This style can be turned on and off by using the ShowWindow or SetWindowPos function.
WS_VSCROLL = 0x00200000, //The window has a vertical scroll bar.
}
public enum GWL_Flags : int
{
GWL_USERDATA = -21,
GWL_EXSTYLE = -20,
GWL_STYLE = -16,
GWL_ID = -12,
GWLP_HWNDPARENT = -8,
GWLP_HINSTANCE = -6,
GWL_WNDPROC = -4,
DWLP_MSGRESULT = 0x0,
DWLP_DLGPROC = 0x4,
DWLP_USER = 0x8
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr GetWindowLongPtr(IntPtr hWnd, GWL_Flags nIndex);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr SetWindowLongPtr(IntPtr hWnd, GWL_Flags nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP_Flags uFlags);
[DllImport("kernel32.dll")]
internal static extern void SetLastError(uint dwErrCode);
}
I have setup the new input system in Unity like so
How can i get the mouse button pressed as enum within the Attack_performed callback?
void Start()
{
Actions.Player.Attack.performed += Attack_performed; ;
}
private void Attack_performed(InputAction.CallbackContext obj)
{
//Convert the context to button enum here...
print((ButtonControl)obj.control); //returns Button:/Mouse/leftButton
}
There is no built-in method because - as it's only used as input in this method as of 1.0.1.0
/// <summary>
/// Set the button mask for the given button.
/// </summary>
/// <param name="button">Button whose state to set.</param>
/// <param name="state">Whether to set the bit on or off.</param>
/// <returns>The same MouseState with the change applied.</returns>
/// <seealso cref="buttons"/>
public MouseState WithButton(MouseButton button, bool state = true)
{
var bit = 1 << (int)button;
if (state)
buttons |= (ushort)bit;
else
buttons &= (ushort)~bit;
return this;
}
But you can cast to it - because it's the exact opposite of the of bitOffset as we can see from the code above, and we can do it like so:
Solution
MouseButton buttonEnum = (MouseButton) context.control.stateBlock.bitOffset;
public enum MouseButton
{
Left, //0
Right, //1
Middle, //2
Forward, //3
Back, //4
}
EDIT: Even though it's possible to do it like so, I would recommend that you create your own enum like that you found - because if Unity change this enum in some way your code would stop working! And it would be hard to find the underlying issue.
I have an application (that always runs in minimized mode) that constantly listens to keys typed on the keyboard.
When certain key is pressed, I want the C# application to post a command on the message queue of the active window to minimize, close, maximize, etc.
I know it is possible to get the handle to the active window, but, how can I post a message on its message queue (as we can do in win32).
Thanks.
You can use interop to call the native WINAPI functions. Using the p/invoke website I have created the following solution:
var proc = Process.GetProcesses().First(p => p.ProcessName.Contains("firefox"));
PostMessageSafe(
new HandleRef(proc, proc.MainWindowHandle),
(uint) WM.WM_SYSCOMMAND,
new IntPtr((int) SysCommands.SC_MAXIMIZE),
IntPtr.Zero);
What I basically do here is find a WindowHandle I'm interested in and then invoke PostMessage with the WM_SYSCOMMAND in Msg and the appropriate syscommand in the wParam, in this case Maximize, with the value 0xF030. The lParam is set to 0.
Please be aware that if your only goal is to change the window state you better use the specialized API endpoint for that, it's called ShowWindow
Its signature looks like this:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
and it is invoked like this:
ShowWindow(proc.MainWindowHandle, ShowWindowCommands.Maximize);
When either of these methods are called, a window from a process named firefox will be maximized.
Here are the helper methods and enums you need as a wrapper around PostMessage
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
// http://www.pinvoke.net/default.aspx/Enums/WindowsMessages.html
public enum WM : uint
{
WM_SYSCOMMAND = 0x0112
}
// http://www.pinvoke.net/default.aspx/Enums/SysCommands.html
enum SysCommands : int
{
SC_SIZE = 0xF000,
SC_MOVE = 0xF010,
SC_MINIMIZE = 0xF020,
SC_MAXIMIZE = 0xF030,
SC_NEXTWINDOW = 0xF040,
SC_PREVWINDOW = 0xF050,
SC_CLOSE = 0xF060,
SC_VSCROLL = 0xF070,
SC_HSCROLL = 0xF080,
SC_MOUSEMENU = 0xF090,
SC_KEYMENU = 0xF100,
SC_ARRANGE = 0xF110,
SC_RESTORE = 0xF120,
SC_TASKLIST = 0xF130,
SC_SCREENSAVE = 0xF140,
SC_HOTKEY = 0xF150,
//#if(WINVER >= 0x0400) //Win95
SC_DEFAULT = 0xF160,
SC_MONITORPOWER = 0xF170,
SC_CONTEXTHELP = 0xF180,
SC_SEPARATOR = 0xF00F,
//#endif /* WINVER >= 0x0400 */
//#if(WINVER >= 0x0600) //Vista
SCF_ISSECURE = 0x00000001,
//#endif /* WINVER >= 0x0600 */
/*
* Obsolete names
*/
SC_ICON = SC_MINIMIZE,
SC_ZOOM = SC_MAXIMIZE,
}
// http://www.pinvoke.net/default.aspx/Enums/ShowWindowCommand.html
enum ShowWindowCommands
{
/// <summary>
/// Hides the window and activates another window.
/// </summary>
Hide = 0,
/// <summary>
/// Activates and displays a window. If the window is minimized or
/// maximized, the system restores it to its original size and position.
/// An application should specify this flag when displaying the window
/// for the first time.
/// </summary>
Normal = 1,
/// <summary>
/// Activates the window and displays it as a minimized window.
/// </summary>
ShowMinimized = 2,
/// <summary>
/// Maximizes the specified window.
/// </summary>
Maximize = 3, // is this the right value?
/// <summary>
/// Activates the window and displays it as a maximized window.
/// </summary>
ShowMaximized = 3,
/// <summary>
/// Displays a window in its most recent size and position. This value
/// is similar to <see cref="Win32.ShowWindowCommand.Normal"/>, except
/// the window is not activated.
/// </summary>
ShowNoActivate = 4,
/// <summary>
/// Activates the window and displays it in its current size and position.
/// </summary>
Show = 5,
/// <summary>
/// Minimizes the specified window and activates the next top-level
/// window in the Z order.
/// </summary>
Minimize = 6,
/// <summary>
/// Displays the window as a minimized window. This value is similar to
/// <see cref="Win32.ShowWindowCommand.ShowMinimized"/>, except the
/// window is not activated.
/// </summary>
ShowMinNoActive = 7,
/// <summary>
/// Displays the window in its current size and position. This value is
/// similar to <see cref="Win32.ShowWindowCommand.Show"/>, except the
/// window is not activated.
/// </summary>
ShowNA = 8,
/// <summary>
/// Activates and displays the window. If the window is minimized or
/// maximized, the system restores it to its original size and position.
/// An application should specify this flag when restoring a minimized window.
/// </summary>
Restore = 9,
/// <summary>
/// Sets the show state based on the SW_* value specified in the
/// STARTUPINFO structure passed to the CreateProcess function by the
/// program that started the application.
/// </summary>
ShowDefault = 10,
/// <summary>
/// <b>Windows 2000/XP:</b> Minimizes a window, even if the thread
/// that owns the window is not responding. This flag should only be
/// used when minimizing windows from a different thread.
/// </summary>
ForceMinimize = 11
}
Currently I need to process Arabic string (اسمي مصير الطفل. من أي بلد أنت) in my project. If the string is displayed in a single line, it is displayed correctly.
However, when the font size is much bigger, the display (I am using label) is wrong.
The string is printed starting from the second line. I found that on the .Net framework we could use drawstring with StringFormatFlags.DirectionRightToLeft. However, that is not available in compact framework. So, how could i print Arabic string in multiple lines? Any advice is appreciated, thanks.
I am sorry, the following is incorrect:
Since WinCE 5 and CompactFramework v 2.0 controls like the Textbox support a RicghtToLeft property (see also http://www.danielmoth.com/Blog/rtl-problem.aspx). So you should ensure you are using CF>=2.0 and WinCE 5 base sdk (ie Windows Mobile 6.x).
Looking at the help for Textbox class, the RightToLeft is marked as NOT AVAILABLE for Compact Framework.
So, you need to write your own DrawText class that splits the words and positions them from right to left.
The native DrawText API supports the uFormat flag DT_RTLREADING (according to the online help for Windows CE 5 Platform Builder):
DT_RTLREADING
Layout in right-to-left reading order for bi-directional text when the font selected into the hdc is a Hebrew or Arabic font. The default reading order for all text is left-to-right.
There is also an option DT_WORDBREAK which I would choose for multiline text and a large enough drawing rectangle.
BUT, that gives the following result using two rectangles and two font sizes to force a wordbreak:
As I can not read that I am not sure, but I assume the wordbreak flag does not work correctly. I assume the second line in the upper part has to start from right too.
Native Code for the above:
...
#define ARABIC_TEXT L"اسمي مصير الطفل. من أي بلد أنت"
#define MulDiv(a,b,c) (((a)*(b))/(c))
...
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
LOGFONT lf;
HFONT hFontNew, hFontOld;
...
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
// Clear out the lf structure to use when creating the font.
memset(&lf, 0, sizeof(LOGFONT));
wsprintf(lf.lfFaceName,L"Arial Unicode MS");
GetClientRect(hWnd, &rect);
hFontNew = CreateFontIndirect(&lf);
hFontOld = (HFONT) SelectObject(hdc, hFontNew);
rect.bottom=rect.bottom/2;
lf.lfHeight=-MulDiv(16, GetDeviceCaps(hdc, LOGPIXELSY), 72);
if(DrawText(hdc, ARABIC_TEXT, -1, &rect, DT_RTLREADING | DT_WORDBREAK)==0){
DEBUGMSG(1, (L"DrawText failed with %i\n", GetLastError()));
}
GetClientRect(hWnd, &rect);
lf.lfHeight=-MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72);
hFontNew = CreateFontIndirect(&lf);
hFontOld = (HFONT) SelectObject(hdc, hFontNew);
rect.top=rect.bottom/2;
if(DrawText(hdc, ARABIC_TEXT, -1, &rect, DT_RTLREADING | DT_WORDBREAK)==0){
DEBUGMSG(1, (L"DrawText failed with %i\n", GetLastError()));
}
EndPaint(hWnd, &ps);
SelectObject(hdc, hFontOld);
DeleteObject(hFontNew);
break;
The following form is an example of calling DrawText (see josef's answer) from C#:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Menu = null;
DrawText(e.Graphics, "اسمي مصير الطفل. من أي بلد أنت", Font, ClientRectangle);
}
private void DrawText(Graphics g, string text, Font font, Rectangle rectangle)
{
IntPtr dc = g.GetHdc();
RECT rect = (RECT)rectangle;
IntPtr hFont = IntPtr.Zero;
IntPtr previousFont = IntPtr.Zero;
try
{
hFont = font.ToHfont();
previousFont = SelectObject(dc, hFont);
DrawText(dc, text, text.Length, ref rect, DrawTextFlags.RightToLeft | DrawTextFlags.Right | DrawTextFlags.WordBreak);
}
finally
{
if (previousFont != IntPtr.Zero)
{
SelectObject(dc, previousFont);
}
if (hFont != IntPtr.Zero)
{
DeleteObject(hFont);
}
g.ReleaseHdc(dc);
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
internal int Left;
internal int Top;
internal int Right;
internal int Bottom;
public static explicit operator RECT(Rectangle rect)
{
return new RECT()
{
Left = rect.Left,
Top = rect.Top,
Right = rect.Right,
Bottom = rect.Bottom
};
}
}
[DllImport("coredll.dll", CharSet = CharSet.Unicode)]
internal static extern int DrawText(IntPtr hdc, string lpStr, int nCount, ref RECT lpRect, DrawTextFlags flags);
[DllImport("coredll.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteObject([In] IntPtr hObject);
[DllImport("coredll.dll")]
internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[Flags]
public enum DrawTextFlags : uint
{
/// <summary>
/// Use default values.
/// </summary>
None = 0x00000000,
/// <summary>
/// Justifies the text to the top of the rectangle.
/// </summary>
Top = 0x00000000,
/// <summary>
/// Aligns text to the left.
/// </summary>
Left = 0x00000000,
/// <summary>
/// Centers text horizontally in the rectangle.
/// </summary>
Center = 0x00000001,
/// <summary>
/// Aligns text to the right.
/// </summary>
Right = 0x00000002,
/// <summary>
/// Centers text vertically. This value is used only with the SingleLine value.
/// </summary>
VerticalCenter = 0x00000004,
/// <summary>
/// Justifies the text to the bottom of the rectangle. This value is used only with the
/// SingleLine value.
/// </summary>
Bottom = 0x00000008,
/// <summary>
/// Breaks words. Lines are automatically broken between words if a word would extend past the
/// edge of the rectangle specified by the lpRect parameter. A carriage return-line feed sequence
/// also breaks the line. If this is not specified, output is on one line.
/// </summary>
WordBreak = 0x00000010,
/// <summary>
/// Displays text on a single line only. Carriage returns and line feeds do not break the line.
/// </summary>
SingleLine = 0x00000020,
/// <summary>
/// Expands tab characters. The default number of characters per tab is eight.
/// </summary>
ExpandTabs = 0x00000040,
/// <summary>
/// Sets tab stops. Bits 15-8 (high-order byte of the low-order word) of the uFormat parameter
/// specify the number of characters for each tab. The default number of characters per tab is
/// eight.
/// </summary>
Tabstop = 0x00000080,
/// <summary>
/// Draws without clipping.
/// </summary>
NoClip = 0x00000100,
/// <summary>
/// Includes the font external leading in line height. Normally, external leading is not included
/// in the height of a line of text.
/// </summary>
ExternalLeading = 0x00000200,
/// <summary>
/// Determines the width and height of the rectangle. If there are multiple lines of text, DrawText
/// uses the width of the rectangle pointed to by the lpRect parameter and extends the base of the
/// rectangle to bound the last line of text. If the largest word is wider than the rectangle, the
/// width is expanded. If the text is less than the width of the rectangle, the width is reduced.
/// If there is only one line of text, DrawText modifies the right side of the rectangle so that it
/// bounds the last character in the line. In either case, DrawText returns the height of the
/// formatted text but does not draw the text.
/// </summary>
CalcRect = 0x00000400,
/// <summary>
/// Turns off processing of prefix characters. Normally, DrawText interprets the mnemonic-prefix
/// character & as a directive to underscore the character that follows, and the mnemonic-prefix
/// characters && as a directive to print a single &. By specifying DT_NOPREFIX, this processing
/// is turned off.
/// </summary>
NoPrefix = 0x00000800,
/// <summary>
/// Uses the system font to calculate text metrics.
/// </summary>
Internal = 0x00001000,
/// <summary>
/// Duplicates the text-displaying characteristics of a multiline edit control. Specifically,
/// the average character width is calculated in the same manner as for an edit control, and
/// the function does not display a partially visible last line.
/// </summary>
EditControl = 0x00002000,
/// <summary>
/// For displayed text, if the end of a string does not fit in the rectangle, it is truncated
/// and ellipses are added. If a word that is not at the end of the string goes beyond the
/// limits of the rectangle, it is truncated without ellipses.
/// </summary>
EndEllipsis = 0x00008000,
/// <summary>
/// Layout in right-to-left reading order for bidirectional text when the font selected into the
/// hdc is a Hebrew or Arabic font. The default reading order for all text is left-to-right.
/// </summary>
RightToLeft = 0x00020000,
/// <summary>
/// Truncates any word that does not fit in the rectangle and adds ellipses.
/// </summary>
WordEllipsis = 0x00040000
}
}
(As you can see I've ignored the return values of each native method)
It seems that there is no solid solution to this issue, so I created a temporary workaround. I am assuming that my Label size is fixed, and if my string size is larger than the width of my Label, I will split it into two. The method I use to split the string is to find a splitting point (currently I am doing it at 0.2 of the total string length).
private void processArabic(string arabicString)
{
string[] stringArray = new string[2];
double index = 0.8 * arabicString.Length;
index = Math.Ceiling(index);
int Index = (int)index;
for (int i = Index; i != 0; i--)
{
if (Char.IsWhiteSpace(arabicString, i))
{
stringArray[1] = arabicString.Substring(0, Index + 1);
stringArray[0] = arabicString.Substring(Index + 1, arabicString.Length - (Index + 1));
break;
}
}
label1.Text = stringArray[0];
label1.Text += "\n";
label1.Text += stringArray[1];
}
Although Arabic string is printed from right to left, index is still counted from left to right. The above snippet is rather rigid, and only apply if you want to split the string into two. I am sure there are lot of ways to improve the above code, any comment/suggestion is welcome.
I am developing an add in for excel. At some point, I can receive async events. I need to be able to show the Excel window if hidden on these events.
I am able to store the Hwnd property, which I believe must be an immutable int/reference to identify my Excel window.
Can someone elaborate on this Hwnd ? and explain how I can show a hidden window from C# using it ?
Thanks in advance folks ;)
UPDATE : shortly, that was the piece of code that sorted my problems :
/// <summary>Enumeration of the different ways of showing a window using
/// ShowWindow</summary>
private enum WindowShowStyle : uint
{
/// <summary>Hides the window and activates another window.</summary>
/// <remarks>See SW_HIDE</remarks>
Hide = 0,
/// <summary>Activates and displays a window. If the window is minimized
/// or maximized, the system restores it to its original size and
/// position. An application should specify this flag when displaying
/// the window for the first time.</summary>
/// <remarks>See SW_SHOWNORMAL</remarks>
ShowNormal = 1,
/// <summary>Activates the window and displays it as a minimized window.</summary>
/// <remarks>See SW_SHOWMINIMIZED</remarks>
ShowMinimized = 2,
/// <summary>Activates the window and displays it as a maximized window.</summary>
/// <remarks>See SW_SHOWMAXIMIZED</remarks>
ShowMaximized = 3,
/// <summary>Maximizes the specified window.</summary>
/// <remarks>See SW_MAXIMIZE</remarks>
Maximize = 3,
/// <summary>Displays a window in its most recent size and position.
/// This value is similar to "ShowNormal", except the window is not
/// actived.</summary>
/// <remarks>See SW_SHOWNOACTIVATE</remarks>
ShowNormalNoActivate = 4,
/// <summary>Activates the window and displays it in its current size
/// and position.</summary>
/// <remarks>See SW_SHOW</remarks>
Show = 5,
/// <summary>Minimizes the specified window and activates the next
/// top-level window in the Z order.</summary>
/// <remarks>See SW_MINIMIZE</remarks>
Minimize = 6,
/// <summary>Displays the window as a minimized window. This value is
/// similar to "ShowMinimized", except the window is not activated.</summary>
/// <remarks>See SW_SHOWMINNOACTIVE</remarks>
ShowMinNoActivate = 7,
/// <summary>Displays the window in its current size and position. This
/// value is similar to "Show", except the window is not activated.</summary>
/// <remarks>See SW_SHOWNA</remarks>
ShowNoActivate = 8,
/// <summary>Activates and displays the window. If the window is
/// minimized or maximized, the system restores it to its original size
/// and position. An application should specify this flag when restoring
/// a minimized window.</summary>
/// <remarks>See SW_RESTORE</remarks>
Restore = 9,
/// <summary>Sets the show state based on the SW_ value specified in the
/// STARTUPINFO structure passed to the CreateProcess function by the
/// program that started the application.</summary>
/// <remarks>See SW_SHOWDEFAULT</remarks>
ShowDefault = 10,
/// <summary>Windows 2000/XP: Minimizes a window, even if the thread
/// that owns the window is hung. This flag should only be used when
/// minimizing windows from a different thread.</summary>
/// <remarks>See SW_FORCEMINIMIZE</remarks>
ForceMinimized = 11
}
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, WindowShowStyle nCmdShow);
static void ContentClick(object obj, EventArgs ea)
{
Microsoft.Office.Interop.Excel.Application oExcelApp = (Microsoft.Office.Interop.Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
oExcelApp.Visible = true;
ShowWindow( (System.IntPtr) Globals.ThisWorkbook.Application.Hwnd, WindowShowStyle.ShowMaximized);
}
hWnd means Window Handle. It's an identifying handle for the window instance.
As for showing it, you could use the user32.ShowWindow API. Here's the P/Invoke signature, courtesy of pinvoke.net:
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
And here's the ShowWindowCommands enum:
/// <summary>Enumeration of the different ways of showing a window using
/// ShowWindow</summary>
private enum WindowShowStyle : uint
{
/// <summary>Hides the window and activates another window.</summary>
/// <remarks>See SW_HIDE</remarks>
Hide = 0,
/// <summary>Activates and displays a window. If the window is minimized
/// or maximized, the system restores it to its original size and
/// position. An application should specify this flag when displaying
/// the window for the first time.</summary>
/// <remarks>See SW_SHOWNORMAL</remarks>
ShowNormal = 1,
/// <summary>Activates the window and displays it as a minimized window.</summary>
/// <remarks>See SW_SHOWMINIMIZED</remarks>
ShowMinimized = 2,
/// <summary>Activates the window and displays it as a maximized window.</summary>
/// <remarks>See SW_SHOWMAXIMIZED</remarks>
ShowMaximized = 3,
/// <summary>Maximizes the specified window.</summary>
/// <remarks>See SW_MAXIMIZE</remarks>
Maximize = 3,
/// <summary>Displays a window in its most recent size and position.
/// This value is similar to "ShowNormal", except the window is not
/// actived.</summary>
/// <remarks>See SW_SHOWNOACTIVATE</remarks>
ShowNormalNoActivate = 4,
/// <summary>Activates the window and displays it in its current size
/// and position.</summary>
/// <remarks>See SW_SHOW</remarks>
Show = 5,
/// <summary>Minimizes the specified window and activates the next
/// top-level window in the Z order.</summary>
/// <remarks>See SW_MINIMIZE</remarks>
Minimize = 6,
/// <summary>Displays the window as a minimized window. This value is
/// similar to "ShowMinimized", except the window is not activated.</summary>
/// <remarks>See SW_SHOWMINNOACTIVE</remarks>
ShowMinNoActivate = 7,
/// <summary>Displays the window in its current size and position. This
/// value is similar to "Show", except the window is not activated.</summary>
/// <remarks>See SW_SHOWNA</remarks>
ShowNoActivate = 8,
/// <summary>Activates and displays the window. If the window is
/// minimized or maximized, the system restores it to its original size
/// and position. An application should specify this flag when restoring
/// a minimized window.</summary>
/// <remarks>See SW_RESTORE</remarks>
Restore = 9,
/// <summary>Sets the show state based on the SW_ value specified in the
/// STARTUPINFO structure passed to the CreateProcess function by the
/// program that started the application.</summary>
/// <remarks>See SW_SHOWDEFAULT</remarks>
ShowDefault = 10,
/// <summary>Windows 2000/XP: Minimizes a window, even if the thread
/// that owns the window is hung. This flag should only be used when
/// minimizing windows from a different thread.</summary>
/// <remarks>See SW_FORCEMINIMIZE</remarks>
ForceMinimized = 11
}
HWnd is a windows handle, in C# it is really an IntPtr type.
Try creating a wrapper class based on IWin32Window and use that when calling Show() e.g.
public class WndWrapper : IWin32Window
{
IntPtr m_Handle;
public WndWrapper(long pHandle)
{
m_Handle = (IntPtr)pHandle;
}
#region IWin32Window Members
public IntPtr Handle
{
get { return m_Handle; }
}
#endregion
}
Then call it like this:
WndWrapper oWnd = new WndWrapper(pHandle);
MyForm oDlg = new MyForm();
oDlg.Show(oWnd);
Just be careful, as HWND elements are unmanaged you will be responsible for ensuring that they are disposed of when required.