C# Windows Mobile 6.5.3 extend Winform MainMenu - c#

what I want to do is to extend the MainMenu of the Windows Mobile Winforms to have a second menu level. If you tip short on the menu button it will do the event action but if you press it longer a second menu level should pop up. The MainMenu is very deficient in its managed functions so I had to find another way. I archived this by deriving MainMenu and add some SubClassing.
public delegate IntPtr Win32WndProc(IntPtr hWnd, int msg, int wParam, int lParam);
[DllImport("coredll.dll", EntryPoint = "FindWindow", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, IntPtr lpWindowName);
[DllImport("coredll.dll")]
public static extern bool EnableWindow(IntPtr hWnd, bool bEnable);
[DllImport("coredll")]
public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, Win32WndProc newProc);
int GWL_WNDPROC = (-4);
int GW_CHILD = 5;
IntPtr _oldToolbarProc;
IntPtr _oldMenuWorkerProc
void Hookup()
{
//find the window to hook
var hWndHooked = FindWindow("HHTaskbar", IntPtr.Zero);
if (hWndHooked == IntPtr.Zero)
return;
//enable the taskbar, not realy necessary
EnableWindow(hWndHooked, true);
//find the menu_worker window
var menuWorkerWnd = FindWindow("menu_worker", IntPtr.Zero);
if (menuWorkerWnd == IntPtr.Zero)
return;
var toolbarWnd = GetWindow(menuWorkerWnd, GW_CHILD);
if (toolbarWnd == IntPtr.Zero)
return;
Win32WndProc newMenuWorker = MenuWorkerProc;
_oldMenuWorkerProc = SetWindowLong(menuWorkerWnd, GWL_WNDPROC, newMenuWorker);
Win32WndProc newToolbar = ToolbarProc;
_oldToolbarProc = SetWindowLong(newToolbarWnd, GWL_WNDPROC, newToolbar);
}
The toolbar subclassing measures the time between WM_LBUTTONDOWN and WM_LBUTTONUP
and depending on the time leaped between these events a context Menu is invoked.
If the context menu is invoked the menu_worker subclassing must suppress the WM_COMMAND of the pressed button.
This works fine for a single window. But if I use it on a second form they will recongize both the same toolbar and menuworker and application crashes.
What I tried is to hook and unhook in the onFocus /onLostFocus events of the parent form.
But sadly onFocus is called before the right window is visible and it also gets the wrong window handle :(
What I did now (I know a very bad hack) is to start a time in the onFocus event and wait for 1000ms and hook it up then. This results in a 50:50 change to hook the right window..
Isn't there a better solution for subclassing the right window?

Related

Dragable window is getting mouse stuck and busy state

I have maui app with blazor I removed the windows default title bar, I'm creating a custom one with blazor
The code works fine, but the mouse is stuck at the point where it was clicked, it is in the busy state
The application moves normally, but the window is stuck to the mouse.
The code is:
Blazor:
<div class="bg-default w-full h-3 fixed" #onmousedown="#MoveWindow">
....
</div>
#code {
[DllImport("user32.dll")]
static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool ReleaseCapture();
const uint WM_SYSCOMMAND = 0x112;
const uint MOUSE_MOVE = 0xF012;
private void MoveWindow()
{
var win = App.Current.Windows.First();
var view = win.Handler.PlatformView;
IntPtr Handle = WinRT.Interop.WindowNative.GetWindowHandle(view);
ReleaseCapture();
DefWindowProc(Handle, WM_SYSCOMMAND, (UIntPtr)MOUSE_MOVE, IntPtr.Zero);
}
}
Does anyone know how I can remove mouse stuck in busy state?
Is there another way to move the maui window other than the code I used?

How to send WM_INPUTLANGCHANGEREQUEST to app with modal window?

I wrote a keyboard switcher, which works well, but fails if current application has modal window opened. On keyboard switch I do the following
hwnd = GetForegroundWindow();
PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, handle);
where
[DllImport("User32.dll", EntryPoint = "PostMessage")]
private static extern int PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
but the language does not change.
How would I accomplish this?
Adding get root owner improved situation, but didn't help completely.
Adding call for GetDesktopWindow didn't help:
hwnd = GetDesktopWindow();
InputLangChangeRequest(hwnd, language);
hwnd = GetRootOwner();
InputLangChangeRequest(hwnd, language);
Code is here https://github.com/dims12/NormalKeyboardSwitcher
Use GetAncestor
Retrieves the owned root window by walking the chain of parent and
owner windows returned by GetParent.
This should return the main UI window if there is a modal window, or a chain of modal window.
hwnd = GetForegroundWindow();
hwnd = GetAncestor(hwnd, GA_ROOTOWNER); //#define GA_ROOTOWNER 3
Apparently WM_INPUTLANGCHANGEREQUEST fails if the target itself is a dialog based application (I don't know why!) To solve the problem you can post WM_INPUTLANGCHANGEREQUEST message to dialog's descendants (in addition to WM_INPUTLANGCHANGEREQUEST message to the dialog itself)
static bool MyEnumProc(IntPtr hwnd, IntPtr lParam)
{
PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, lParam);
return true;
}
static void Foo()
{
//Greek input for testing:
var hkl = LoadKeyboardLayout("00000408", KLF_ACTIVATE);
var hwnd = GetForegroundWindow();
if (hwnd != null)
{
hwnd = GetAncestor(hwnd, GA_ROOTOWNER);
PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, (IntPtr)hkl);
StringBuilder buf = new StringBuilder(100);
GetClassName(hwnd, buf, 100);
//if this is a dialog class then post message to all descendants
if (buf.ToString() == "#32770")
EnumChildWindows(hwnd, MyEnumProc, (IntPtr)hkl);
}
}

GetFocus - Win32api help

i am trying to grab the selected text from the open form on a users machine. Currently i have tried using GetFocus which is defined as
'[DllImport("user32.dll")]
static extern int GetFocus();'
In the api it says - Retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue. Which explains why my app can grab the selected text from a window thats part of my app, but not one thats external, like a pdf for example.
What alternative win32 method is available for me to use that would fit this purpose?
Thanks.
edit: this is the attempt at the moment
[DllImport("user32.dll")]
static extern int GetFocus();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(int hWnd, int ProcessId);
[DllImport("user32.dll")]
static extern int GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern int SendMessage(int hWnd, int Msg, int wParam, StringBuilder lParam);
// second overload of SendMessage
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, uint Msg, out int wParam, out int lParam);
const int WM_SETTEXT = 12;
const int WM_GETTEXT = 13;
private static string PerformCopy()
{
try
{
//Wait 5 seconds to give us a chance to give focus to some edit window,
//notepad for example
System.Threading.Thread.Sleep(1000);
StringBuilder builder = new StringBuilder(500);
int foregroundWindowHandle = GetForegroundWindow();
uint remoteThreadId = GetWindowThreadProcessId(foregroundWindowHandle, 0);
uint currentThreadId = GetCurrentThreadId();
//AttachTrheadInput is needed so we can get the handle of a focused window in another app
AttachThreadInput(remoteThreadId, currentThreadId, true);
//Get the handle of a focused window
int focused = GetFocus();
//Now detach since we got the focused handle
AttachThreadInput(remoteThreadId, currentThreadId, false);
//Get the text from the active window into the stringbuilder
SendMessage(focused, WM_GETTEXT, builder.Capacity, builder);
return builder.ToString();
}
catch (System.Exception oException)
{
throw oException;
}
}
Check GetForegroundWindow.
I don't think you have much chance of succeeding with your current approach. I'm pretty sure there's no single general purpose API for getting hold of the current selection. I believe this because each application can implement text selection in its own way.
As an alternative solution you should consider using a clipboard listener. Listen for changes to the clipboard contents and whenever text is added you can suck it out of the clipboard and put it in your app's window.
I think this is a job for UI Automation (the API screen readers use). Here's a post that get's the selected text in C#.

How can I get functionality similar to Spy++ in my C# app?

I'm interested in working on a plugin for Keepass, the open-source password manager. Right now, Keepass currently detects what password to copy/paste for you based off of the window title. This prevents Keepass from detecting the current password you need for apps that don't actively update their window title based on the current site (Chrome for instance).
How can I walk through another processes window elements (buttons, labels, textbox) similar to how Spy++ works? When you run Spy++ you can hover over other programs windows and get all kinds of information about various properties concerning various controls (labels, textboxes, etc). Ideally, I'd like my Keepass plugin to enhance the current window detection by walking through the active window's elements in an effort to find a matching account to copy/paste the password.
How can I walk other processes window elements and be able to retrieve label and textbox values using C#?
I've being answering similar questions like this here: How can I detect if a thread has windows handles?. Like it states, the main idea is to enumerate through process windows and their child windows using EnumWindows and EnumChildWindows API calls to get window handles and then call GetWindowText or SendDlgItemMessage with WM_GETTEXT to get window text. I've modified code to make an example which should be doing what you need (sorry it's a bit long :). It iterates through processes and their windows and dumps window text into console.
static void Main(string[] args)
{
foreach (Process procesInfo in Process.GetProcesses())
{
Console.WriteLine("process {0} {1:x}", procesInfo.ProcessName, procesInfo.Id);
foreach (ProcessThread threadInfo in procesInfo.Threads)
{
// uncomment to dump thread handles
//Console.WriteLine("\tthread {0:x}", threadInfo.Id);
IntPtr[] windows = GetWindowHandlesForThread(threadInfo.Id);
if (windows != null && windows.Length > 0)
foreach (IntPtr hWnd in windows)
Console.WriteLine("\twindow {0:x} text:{1} caption:{2}",
hWnd.ToInt32(), GetText(hWnd), GetEditText(hWnd));
}
}
Console.ReadLine();
}
private static IntPtr[] GetWindowHandlesForThread(int threadHandle)
{
_results.Clear();
EnumWindows(WindowEnum, threadHandle);
return _results.ToArray();
}
// enum windows
private delegate int EnumWindowsProc(IntPtr hwnd, int lParam);
[DllImport("user32.Dll")]
private static extern int EnumWindows(EnumWindowsProc x, int y);
[DllImport("user32")]
private static extern bool EnumChildWindows(IntPtr window, EnumWindowsProc callback, int lParam);
[DllImport("user32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
private static List<IntPtr> _results = new List<IntPtr>();
private static int WindowEnum(IntPtr hWnd, int lParam)
{
int processID = 0;
int threadID = GetWindowThreadProcessId(hWnd, out processID);
if (threadID == lParam)
{
_results.Add(hWnd);
EnumChildWindows(hWnd, WindowEnum, threadID);
}
return 1;
}
// get window text
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);
private static string GetText(IntPtr hWnd)
{
int length = GetWindowTextLength(hWnd);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
// get richedit text
public const int GWL_ID = -12;
public const int WM_GETTEXT = 0x000D;
[DllImport("User32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int index);
[DllImport("User32.dll")]
public static extern IntPtr SendDlgItemMessage(IntPtr hWnd, int IDDlgItem, int uMsg, int nMaxCount, StringBuilder lpString);
[DllImport("User32.dll")]
public static extern IntPtr GetParent(IntPtr hWnd);
private static StringBuilder GetEditText(IntPtr hWnd)
{
Int32 dwID = GetWindowLong(hWnd, GWL_ID);
IntPtr hWndParent = GetParent(hWnd);
StringBuilder title = new StringBuilder(128);
SendDlgItemMessage(hWndParent, dwID, WM_GETTEXT, 128, title);
return title;
}
hope this helps, regards
Have a look at this article here which contains information about the Managed Spy and why the author wrote the tool.
You can use EnumWindows to find every top-level Chrome window and then call EnumChildWindows recursively (see Jeroen Wiert Pluimers' comment) to get every child of the main window. Alternatively, once you have the main Chrome window, you can use GetWindow to manually navigate the tree since you probably know what you're looking for (3rd child's children collection or something similar).
Once you find your window, you can use SendMessage with a WM_GETTEXT parameter to read the window's label.
You can use HWndSpy. Source code is here.
For the functionality of pointing to a window. You need to SetCapture() so that you get mouse messages that are outside of your window. Then use WindowFromPoint() to convert a mouse position to a Window. You will need to convert the moust position from client coordinates to window coordinates first.
If you try an call SetCapture() anywhere but on a mouse click message, you will probably be ignored. This is the reason that Spy++ makes you click on an Icon and drag and drop it on the window you want to point to.

.Net Console Application in System tray

Is there a way I can put a console application in the system tray when minimizing ?
Yes, you can do this.
Create a Windows Forms application and add a NotifyIcon component.
Then use the following methods (found on MSDN) to allocate and display a Console
[DllImport("kernel32.dll")]
public static extern Boolean AllocConsole();
[DllImport("kernel32.dll")]
public static extern Boolean FreeConsole();
[DllImport("kernel32.dll")]
public static extern Boolean AttachConsole(Int32 ProcessId);
When your console is onscreen, capture the minimize button click and use it to hide the console window and update the Notify icon. You can find your window using the following methods (found on MSDN):
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
// Find window by Caption only. Note you must pass IntPtr.Zero as the first parameter.
// Also consider whether you're being lazy or not.
[DllImport("user32.dll", EntryPoint="FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
Be sure to call FreeConsole whenever you're ready to close the app.
using System.Windows.Forms;
using System.Drawing;
static NotifyIcon notifyIcon = new NotifyIcon();
static bool Visible = true;
static void Main(string[] args)
{
notifyIcon.DoubleClick += (s, e) =>
{
Visible = !Visible;
SetConsoleWindowVisibility(Visible);
};
notifyIcon.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
notifyIcon.Visible = true;
notifyIcon.Text = Application.ProductName;
var contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("Exit", null, (s, e) => { Application.Exit(); });
notifyIcon.ContextMenuStrip = contextMenu;
Console.WriteLine("Running!");
// Standard message loop to catch click-events on notify icon
// Code after this method will be running only after Application.Exit()
Application.Run();
notifyIcon.Visible = false;
}
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public static void SetConsoleWindowVisibility(bool visible)
{
IntPtr hWnd = FindWindow(null, Console.Title);
if (hWnd != IntPtr.Zero)
{
if (visible) ShowWindow(hWnd, 1); //1 = SW_SHOWNORMAL
else ShowWindow(hWnd, 0); //0 = SW_HIDE
}
}
A console has no window to minimize by itself. It runs in a command prompt window. You might hook the window messages and hide the window on minimize. In your application it's possible to add a tray icon just the same as you would do it in a windows application. Well, somehow this smells...
But: I'm not sure why you want to do this. A console application is by design different to a windows application. Hence, maybe it's an option to change the app to be a windows form application?
[DllImport("user32.dll")]
internal static extern bool SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, Int32 lParam);
static Int32 WM_SYSCOMMAND = 0x0112;
static Int32 SC_MINIMIZE = 0x0F020;
static void Main(string[] args)
{
SendMessage(Process.GetCurrentProcess().MainWindowHandle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
}
I use TrayRunner for exactly this purpose. Essentially, it wraps a console application capturing all output. But when minimized, it minimizes to the system tray instead of the task bar. You can even customize what icon to show when minimized. I use it for things like Tomcat or Apache to free up space on my taskbar without running them as Windows Services.
You can't hide a console application because it does not actually have a window to hide, seeing as how it is running in the console (the console itself is just a window of the console, not the app running in it)

Categories

Resources