Post message to an active window/application from a c# application - c#

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
}

Related

Start an external process inside a panel without other apps losing focus

I have this code to run an exe, catch the hWnd, and move it inside a panel of my C# app.
All is ok, but this process must be restarted every hour, and when I do this by killing it and restarting it, it takes the active focus.
If I am writing something in another app, or watching a video in fullscreen, it causing me to exit fullscreen, or me to write inside this new process instead of Word or whatever...
How I can avoid the launched exe from taking focus when restarted?
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
Funzioni.HWnd = IntPtr.Zero;
PSI = new ProcessStartInfo(Funzioni.AppPath)
{
CreateNoWindow = true,
RedirectStandardInput = false,
RedirectStandardOutput = false,
RedirectStandardError = false
};
P = Process.Start(PSI);
int MaxCount = 10000;
int Count = 0;
while (Funzioni.HWnd == IntPtr.Zero || Count > MaxCount)
{
P.WaitForInputIdle();
P.Refresh();
Funzioni.HWnd = P.MainWindowHandle;
Count++;
}
if (Funzioni.HWnd == IntPtr.Zero) throw new ApplicationException("The process is taking long to start");
Funzioni.SetParent(Funzioni.HWnd, Pnl_Centrale.Handle);
Funzioni.MoveWindow(Funzioni.HWnd, Funzioni.ExePosX, Funzioni.ExePosY, Funzioni.ExeLarghezza, Funzioni.ExeAltezza - Funzioni.AltezzaToolBar, true);
The ProcessStartInfo properties you are setting only applies to console applications. For a GUI application you must set the ProcessStartInfo.WindowStyle property to Hidden.
It is possible that this will change how MainWindowHandle works because Win32 does not actually have a main window concept. You probably have to p/invoke FindWindow or EnumWindows+GetWindowThreadProcessId.
Solved by myself in this way:
Funzioni.HWnd = IntPtr.Zero;
// Start hidden the process
PSI = new ProcessStartInfo(Funzioni.AppPath)
{
CreateNoWindow = true,
RedirectStandardInput = false,
RedirectStandardOutput = false,
RedirectStandardError = false,
WindowStyle = ProcessWindowStyle.Hidden
};
P = Process.Start(PSI);
int MaxCount = 10000;
int Count = 0;
Thread.Sleep(500);
while (Funzioni.HWnd == IntPtr.Zero || Count > MaxCount)
{
P.WaitForInputIdle();
P.Refresh();
// Get the hidden main handle
Funzioni.HWnd = Funzioni.EnumerateProcessWindowHandles(P.Id).First();
Count++;
}
if (Funzioni.HWnd == IntPtr.Zero) throw new ApplicationException("The process is taking long to start");
// Set the parent exe
Funzioni.SetParent(Funzioni.HWnd, Pnl_Centrale.Handle);
// Set the window of the nested exe in no-top most and not active
Funzioni.SetWindowPos(Funzioni.HWnd, (IntPtr)SpecialWindowHandles.HWND_NOTOPMOST,
Funzioni.ExePosX, Funzioni.ExePosY, Funzioni.ExeLarghezza, Funzioni.ExeAltezza - Funzioni.AltezzaToolBar,
(uint)SetWindowPosFlags.SWP_NOACTIVATE | (uint)SetWindowPosFlags.SWP_NOOWNERZORDER);
// Move again the the window in the desired position (i don't know why the function above don't work if using "NOTOPMOST"
Funzioni.MoveWindow(Funzioni.HWnd, Funzioni.ExePosX, Funzioni.ExePosY, Funzioni.ExeLarghezza, Funzioni.ExeAltezza - Funzioni.AltezzaToolBar, true);
P.Refresh();
// Show the back the hidden process/ese/window
Funzioni.ShowWindow(Funzioni.HWnd, 1);
WinAPI:
#region WinApi
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
internal delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
internal static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn,
IntPtr lParam);
internal static IEnumerable<IntPtr> EnumerateProcessWindowHandles(int processId)
{
var handles = new List<IntPtr>();
foreach (ProcessThread thread in Process.GetProcessById(processId).Threads)
EnumThreadWindows(thread.Id,
(hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
return handles;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool InvalidateRect(IntPtr hWnd, IntPtr rect, bool bErase);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UpdateWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, UInt32 uFlags);
#endregion
Enums:
public enum SpecialWindowHandles
{
// ReSharper disable InconsistentNaming
/// <summary>
/// Places the window at the top of the Z order.
/// </summary>
HWND_TOP = 0,
/// <summary>
/// Places the window at the bottom of the Z order. If the hWnd parameter identifies a topmost window, the window loses its topmost status and is placed at the bottom of all other windows.
/// </summary>
HWND_BOTTOM = 1,
/// <summary>
/// Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated.
/// </summary>
HWND_TOPMOST = -1,
/// <summary>
/// Places the window above all non-topmost windows (that is, behind all topmost windows). This flag has no effect if the window is already a non-topmost window.
/// </summary>
HWND_NOTOPMOST = -2
// ReSharper restore InconsistentNaming
}
[Flags]
public enum SetWindowPosFlags : uint
{
// ReSharper disable InconsistentNaming
/// <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,
/// <summary>
/// Prevents generation of the WM_SYNCPAINT message.
/// </summary>
SWP_DEFERERASE = 0x2000,
/// <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>
/// Hides the window.
/// </summary>
SWP_HIDEWINDOW = 0x0080,
/// <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>
/// 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>
/// Retains the current position (ignores X and Y parameters).
/// </summary>
SWP_NOMOVE = 0x0002,
/// <summary>
/// Does not change the owner window's position in the Z order.
/// </summary>
SWP_NOOWNERZORDER = 0x0200,
/// <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>
/// 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>
/// Retains the current size (ignores the cx and cy parameters).
/// </summary>
SWP_NOSIZE = 0x0001,
/// <summary>
/// Retains the current Z order (ignores the hWndInsertAfter parameter).
/// </summary>
SWP_NOZORDER = 0x0004,
/// <summary>
/// Displays the window.
/// </summary>
SWP_SHOWWINDOW = 0x0040,
// ReSharper restore InconsistentNaming
}
Unfortunately, sometimes (not ever) the GUI of the nested app is not draw correctly, forcing me to restart it manually after the auto-restart every 60 mins. I have used [DllImport("user32.dll")] static extern bool UpdateWindow(IntPtr hWnd); but without luck. Any other redraw/function are not working. There is a way to force redraw before show up?
Also, the code above, make the Windows status bar to pop up while are in full screen on (for example) YouTube. Any suggestions to avoid this too?

Printing Arabic string correctly in multiple lines

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.

C# show hidden window

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.

Get current cursor lower left position so that tooltip could be displayed properly

I'm trying to display the tooltip by calling "ToolTip.Show(String, IWin32Window, Point)", but I wanted to do it like what Windows explorer does - displays the tooltip at the lower left corner of the cursor.
I could get the mouse position by "MousePosition", but how could I get its lower left corner position?
Thanks,
If nobody comes up with a better answer you can try this:
toolTip1.Show("Am I where you want me to be?", this, this.PointToClient(MousePosition).X,
this.PointToClient(MousePosition).Y + Cursor.Size.Height * 2);
Adjust the text positioning by playing with the x/y parameters. It works on my machine but I'm not sure how it would look under different settings.
ToolTip fun tip: put this line in your Form's MouseMove event.
I think Explorer puts the tooltip under the cursor's hotspot so you don't have to correct the X-position. This looked good:
private void panel1_MouseClick(object sender, MouseEventArgs e) {
int x = e.X;
int y = e.Y + Cursor.Current.Size.Height - Cursor.Current.HotSpot.Y;
toolTip1.Show("test", panel1, x, y);
}
The only way to do this is to scan the cursors MASK and find the distance between the last set pixel in the cursor mask and the cursors Y hotspot, I had to do this up today, so heres the code:
#define useUnsafe
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System;
using System.Windows.Forms;
namespace Utils
{
/// <summary>
/// Provides extension methods for the Cursor class
/// </summary>
/// <remarks>By Aaron Murgatroyd</remarks>
public static class CursorExtensionMethods
{
#region API Functions
/// <summary>
/// Contains the icon information for a Windows API icon
/// </summary>
private struct IconInfo
{
public bool fIcon;
public int xHotspot;
public int yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
}
/// <summary>
/// Gets the icon information for a Windows API icon
/// </summary>
/// <param name="hIcon">The icon to get the info for</param>
/// <param name="pIconInfo">The object to receive the info</param>
/// <returns>True on success, false on failure</returns>
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
[DllImport("gdi32.dll")]
static extern bool DeleteObject(IntPtr hObject);
#endregion
#region Private Static Methods
/// <summary>
/// Scans bits in bitmap data for a set or unset bit
/// </summary>
/// <param name="byteData">The pointer to the first byte of the first scanline</param>
/// <param name="start">The vertical position to start the scan</param>
/// <param name="lineInc">The number of bytes to move per line</param>
/// <param name="maxLines">The number of lines to scan</param>
/// <param name="set">True to scan for set bits, false to scan for unset bits</param>
/// <param name="fromBottom">True to scan from the bottom of the bitmap, false to scan from the top</param>
/// <returns>The number of lines scanned before a bit was found, or -1 if none found before reaching max lines</returns>
#if useUnsafe
private static unsafe int ScanBits(IntPtr byteData, int start, int lineInc, int maxLines, bool set, bool fromBottom)
#else
private static int ScanBits(IntPtr byteData, int start, int lineInc, int maxLines, bool set, bool fromBottom)
#endif
{
// Calculate the starting byte of the first scanline
#if useUnsafe
byte* lbLine = ((byte*)byteData) + (start * lineInc);
#else
int lbLine = ((int)(byteData) + (start * lineInc));
#endif
int liLine = 0;
// Use lineInc to determines bytes per line
int liBytesPerLine = (lineInc < 0 ? -lineInc : lineInc);
// If we want to search in reverse order
if (fromBottom)
{
// Move to the START of the line
lbLine += lineInc * (maxLines - 1);
// Negate the line increment
lineInc = -lineInc;
}
while (maxLines > 0)
{
// Setup the line scan
#if useUnsafe
byte* lbData = lbLine;
#else
int lbData = lbLine;
#endif
int liByte = liBytesPerLine;
// For each byte in the line
while (liByte > 0)
{
#if !useUnsafe
byte lbByte = Marshal.ReadByte((IntPtr)lbData);
#endif
// If we want set bits, and a bit is set
#if useUnsafe
if (set && *lbData != 0)
#else
if (set && lbByte != 0)
#endif
// Return the line number
return liLine;
else
// If we want unset bits and any bits arent set
#if useUnsafe
if (!set && *lbData != byte.MaxValue)
#else
if (!set && lbByte != byte.MaxValue)
#endif
// Return the line number
return liLine;
// Next byte for scan line
liByte--;
lbData++;
}
// Next scan line
liLine++;
maxLines--;
lbLine += lineInc;
}
// If all lines were scanned, return -1
if (maxLines == 0)
return -1;
else
// Return number of lines scanned
return liLine;
}
#endregion
#region Public Static Methods
/// <summary>
/// Gets the number of pixels between the Y hotspot
/// and the last physical line of a cursor
/// </summary>
/// <param name="cursor">The cursor to scan</param>
/// <returns>
/// The number of lines between the Y hotspot
/// and the last physical line of the cursor
/// </returns>
public static int GetBaseLineHeight(this Cursor cursor)
{
return GetBaseLine(cursor) - cursor.HotSpot.Y;
}
/// <summary>
/// Gets the physical base line of the cursor, that is,
/// the distance between the top of the virtual cursor
/// and the physical base line of the cursor
/// </summary>
/// <param name="cursor">The cursor to scan</param>
/// <returns>The number of lines between the top of the virtual cursor
/// and the physical base line of the curosr</returns>
public static int GetBaseLine(this Cursor cursor)
{
IconInfo liiInfo = new IconInfo();
if (!GetIconInfo(cursor.Handle, ref liiInfo))
return cursor.Size.Height;
Bitmap lbmpBitmap = Bitmap.FromHbitmap(liiInfo.hbmMask);
try
{
BitmapData lbdData = lbmpBitmap.LockBits(
new Rectangle(0, 0, lbmpBitmap.Width, lbmpBitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);
try
{
// Calculate number of lines in AND scan before any found
int liLine = ScanBits(lbdData.Scan0, 0, lbdData.Stride, cursor.Size.Height, false, true);
// If no AND scan bits found then scan for XOR bits
if (liLine == -1 && lbdData.Height == cursor.Size.Height * 2)
liLine = ScanBits(lbdData.Scan0, cursor.Size.Height, lbdData.Stride, cursor.Size.Height, true, true);
return cursor.Size.Height-liLine;
}
finally
{
lbmpBitmap.UnlockBits(lbdData);
}
}
finally
{
DeleteObject(liiInfo.hbmMask);
DeleteObject(liiInfo.hbmColor);
lbmpBitmap.Dispose();
}
}
#endregion
}
}
You can undefine the conditional define "useUnsafe" at the top so you dont have to enable unsafe code if you like, but be warned it will run slower in this mode.
So this uses extension methods, so all you have to do is add Cursor.Current.GetBaseLineHeight() to your Cursor.Position.Y and that will be the first blank line under the cursor.
ie.
Point lptBlankLineUnderCursor = new Point(Cursor.Position.X, Cursor.Position.Y + Cursor.Current.GetBaseLineHeight())

FlashWindowEx FLASHW_STOP still keeps taskbar colored

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.

Categories