In Visual Studio I've created a Word 2016 Document project. To this document I've added a custom ActionsPane control. The only thing this control does is adding a PlainTextContentControl to the active document.
if (Globals.ThisDocument.Content.Application.ActiveDocument == null) return;
var tagControl = Globals.ThisDocument.Controls.AddPlainTextContentControl(Guid.NewGuid().ToString());
tagControl.PlaceholderText = #"PLACEHOLDER";
tagControl.LockContents = true;
This all works fine, the plaintextcontrol is added and selected in the Word document. But what I want is that the control is added and that the cursor will jump to the end of the control so a user can directly start typing. The newly added control is automatically selected. How can I turn this of?
I have already tried:
var range = Globals.ThisDocument.Content;
range.Application.Selection.Collapse();
Can anyone help me out here? Thanks.
Edit:
Als tried this solution.
private static IntPtr documentHandle;
public delegate bool EnumChildProc(IntPtr hwnd, int lParam);
[DllImport("user32.dll")]
public static extern System.IntPtr SetFocus(System.IntPtr hWnd);
[DllImport("user32.dll")]
public static extern int EnumChildWindows(IntPtr hWndParent, EnumChildProc callback, int lParam);
[DllImport("user32.dll")]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder title, int count);
private static bool EnumChildWindow_Handle(IntPtr handle, int lparam)
{
StringBuilder s = new StringBuilder(50);
GetWindowText(handle, s, 50);
Debug.WriteLine(s.ToString());
if (s.ToString() == "Microsoft Word-document")
{
documentHandle = handle;
}
return true;
}
private void MoveCursorToEndOfLastAddedTag(PlainTextContentControl ctrl)
{
EnumChildProc EnumChildWindow = new EnumChildProc(EnumChildWindow_Handle);
EnumChildWindows(Process.GetCurrentProcess().MainWindowHandle, EnumChildWindow, 0);
SetFocus(documentHandle);
}
This also doesn't work.
Finally I have success. It's not the most clean way, but it works like a charm. The only code I made is this:
private void MoveCursorToEndOfLastAddedTag(PlainTextContentControl ctrl)
{
System.Windows.Forms.SendKeys.Send("{F10}");
System.Windows.Forms.SendKeys.Send("{F10}");
System.Windows.Forms.SendKeys.Send("{RIGHT}");
}
It sends 2 times the F10 key. First time the focus is set to the ribbon, the second time the focus is given back to the document. With the right key I remove the selection from the PlainTextContentControl.
Thank you all for your help.
Related
First of all, have in mind that Im a beginner.
With that said, Im trying to press a button in an external application with user32.dll. I have tried a lot of solutions but cant find anything that works.
I am using 3 DllImport because I want to bring the window to the front aswell (This works fine)
It looks like this:
[DllImportAttribute("User32.dll")]
private static extern int FindWindow(String ClassName, String
WindowName);
[DllImportAttribute("User32.dll")]
private static extern IntPtr SetForegroundWindow(int fgr);
[DllImport("user32.dll")]
static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, int
lParam);
const int BN_CLICKED = 245;
When I click a button, it will bring the application to the front, like this:
private void button1_Click(object sender, EventArgs e)
{
int fgr = FindWindow("TAssistMainFrm", null);
if (fgr > 0) //If found
{
MessageBox.Show("Window found!");
SetForegroundWindow(fgr);
}
else //Not Found
{
MessageBox.Show("Window Not Found!");
}
}
As I said, this works absolutly fine!
Heres the problem.
I want to press a button with ClassNN TButton10
I have tried:
SendMessage(TButton10, BN_CLICKED, 0, 0);
And a lot of other things, but Im guessing that I need to find TButton10 and declare it first. How should I do that?
Anyone that can help me out with code that works, and an explanation of the code?
Thanks a lot!
Opening a Webdocument in the default browser is a qeustion that have been answered a minnion times. But I have a twist to the question:
How can I in C# open or Refresh a html document in the default browser.
If I try some thing like this:
private Process ShowFile(string htmlFilename)
{
var myProcess = new Process();
try
{
// true is the default, but it is important not to set it to false
myProcess.StartInfo.UseShellExecute = true;
myProcess.StartInfo.FileName = htmlFilename;
myProcess.Start();
}
catch (Exception e)
{
}
return myProcess;
}
A new window is opened each time.
* EDIT *
I have tried this but the Browser doesn't refresh
public delegate bool EnumThreadWindowsCallback(int hWnd, int lParam);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData);
[DllImport("user32.dll")]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static public extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
private bool FindWindowByRx(int hWnd, int lParam)
{
Regex pattern = new Regex("Seneste nyt", RegexOptions.IgnoreCase);
StringBuilder windowTitle = new StringBuilder(256);
GetWindowText(hWnd, windowTitle, 255);
if (pattern.IsMatch(windowTitle.ToString()))
{
SetForegroundWindow(new IntPtr(hWnd));
return false; // abort search
}
else
{
return true; // keep on searching
}
}
private bool ActivateWindow()
{
return EnumWindows(new EnumThreadWindowsCallback(FindWindowByRx), new IntPtr());
uint KEYEVENTF_KEYUP = 2;
byte VK_CONTROL = 0x11;
byte VK_F5= 0x74;
keybd_event(VK_CONTROL, 0, 0, 0);
keybd_event(VK_F5, 0, 0, 0);
keybd_event(VK_F5, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
}
It only gets focus.
First, the browser tab containing the page you want to refresh must be the selected tab. According to this SO question you can't activate the tab containing a certain url. You can find all the urls of the opened tabs but you can't select the tab you want.
So, assuming the tab is already selected, you can just find and activate the browser's window and send it a combination of keys similar to Get the selected Text from other Process. Only instead of ctrl+c you can send a ctr+l (this puts the cursor on the address field) and enter (this will refresh the page) for Firefox, for example.
Alternatively, also for Firefox at least, you can send a ctrl+w, which closes the current selected tab, and then open a new page as your code already does, which in your case will be exactly the same page you've just closed.
Or, you can open your page in a new browser instance (not a new tab). When you want to refresh it, you can find that browser window by name and close it. Then reopen a new browser window. This would be a solution in case the tab you're interested might not currenty be the selected tab in your browser
In Visual C#, I'm trying to take text from multiple textboxes (one at a time) and paste them into Notepad. I do this by copying to the clipboard, alt-tabbing, and then pasting into notepad...then again for the other textboxes. This code represents this idea:
subBox1.SelectAll();
subBox1.Copy();
SendKeys.Send("%{TAB}"); // alt+tab
SendKeys.Send("^v"); // paste
SendKeys.Send("{TAB}"); // tab
subBox2.SelectAll();
subBox2.Copy();
SendKeys.Send("^v");
SendKeys.Send("{TAB}");
subBox3.SelectAll();
subBox3.Copy();
SendKeys.Send("^v");
SendKeys.Send("{TAB}");
As you can see, this copies and pastes from three textboxes (named subBox1, 2, and 3). But, for some reason, only the last textbox's contents are getting copied over. This also happens if I comment out the third box...in that case, only the second textbox's content gets copied over. I've tried using the SelectAll() and Copy() as you see here, as well as the Clipboard class. Both have the same issue.
For example, if the textbox contents are "asdf", "qwer", and "zxcv" respectively, all I see is "zxcv" three times.
Any idea why this is happening? I've been stuck on this for about an hour now and have no idea what's going on.
Thanks a ton!
SendKeys doesn't wait for the other application to process the keys you send, so by the time notepad gets around to processing your keypresses, your program has already copied subBox3's text over the top of the other texts.
You need to use SendWait instead.
As well, instead of sending Alt+Tab, you could use something like this:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
// ...
SetForegroundWindow(FindWindow(null, "Untitled - Notepad"));
I'd use SendMessage for more accurate results. To use SendMessage, you first need a valid window handle to the text area of Notepad. This can be done in a variety of ways, but I prefer just using my simple child lookup function.
You will need the following namespace imports and PInvoke declarations:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
//pinvoke
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern bool GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
private static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hParent, delChildWndProc callback, IntPtr lpParam);
//delegate callback for EnumChildWindows:
[return:MarshalAs(UnmanagedType.Bool)]
private delegate bool delChildWndProc(IntPtr hWnd, IntPtr lParam);
Now, onto the child window lookup. Basically works similar to FindWindowEx, but I wanted to write my own, and it retrieves multiple windows which can be nice. It uses the following wrapper class to describe information between calls:
private class WindowLookup
{
public string LookupName { get; private set; }
public List<IntPtr> MatchedChildren { get; private set; }
public int Depth { get; set; }
public int MaxDepth { get; set; }
public WindowLookup(string lookup, int maxdepth)
{
this.MatchedChildren = new List<IntPtr>();
this.LookupName = lookup;
this.MaxDepth = maxdepth;
if (this.MaxDepth > 0)
this.MaxDepth++; //account for the depth past the parent control.
this.Depth = 0;
}
}
And then the following functions do all the work:
private static List<IntPtr> FindAllWindows(IntPtr hParent, string className, int maxdepth = 0)
{
var lookup = new WindowLookup(className, maxdepth);
var gcAlloc = GCHandle.Alloc(lookup);
try
{
LookupChildProc(hParent, GCHandle.ToIntPtr(gcAlloc));
}
finally
{
if (gcAlloc.IsAllocated)
gcAlloc.Free();
}
return lookup.MatchedChildren;
}
private static bool LookupChildProc(IntPtr hChild, IntPtr lParam)
{
var handle = GCHandle.FromIntPtr(lParam);
WindowLookup lookup = null;
if (handle.IsAllocated && (lookup = handle.Target as WindowLookup) != null)
{
if (lookup.Depth < lookup.MaxDepth || lookup.MaxDepth == 0)
{
lookup.Depth++;
var builder = new StringBuilder(256);
if (GetClassName(hChild, builder, builder.Capacity) && builder.ToString().ToLower() == lookup.LookupName.ToLower())
lookup.MatchedChildren.Add(hChild);
EnumChildWindows(hChild, LookupChildProc, lParam);
}
}
return true;
}
You don't need to worry about the implementation of these functions too much, they'll work as-is. The key thing is that using these functions, you can find the handle to notepad's Edit window (the text area you type in) very easily.
var notepads = Process.GetProcessesByName("notepad");
if (notepads.Length > 0)
{
foreach(var notepad in notepads) //iterate through all the running notepad processes. Of course, you can filter this by processId or whatever.
{
foreach(var edit in FindAllWindows(notepad.MainWindowHandle, "Edit"))
{
//next part of the code will go here, read on.
}
}
}
Now, where I left the code was in the middle of a loop through the "Edit" windows of each notepad process running at the time. Now that we have a valid window handle, we can use SendMessage to send stuff to it. In particular, appending text. I wrote the following function to handle appending text to a remote control:
private static void AppendWindowText(IntPtr hWnd, string text)
{
if (hWnd != IntPtr.Zero)
{
//for your reference, 0x0E (WM_GETTEXTLENGTH), 0xB1 (EM_SETSEL), 0xC2 (EM_REPLACESEL)
int len = SendMessage(hWnd, 0x000E, IntPtr.Zero, IntPtr.Zero).ToInt32();
var unmanaged = Marshal.StringToHGlobalAuto(text);
SendMessage(hWnd, 0x00B1, new IntPtr(len), new IntPtr(len));
SendMessage(hWnd, 0x00C2, IntPtr.Zero, unmanaged);
Marshal.FreeHGlobal(unmanaged);
}
}
Now that we have our AppendWindowText function, you can add a function call to it in the nested loop above (where I put the comment):
AppendWindowText(edit, "Some text here");
And there you have it. It's a bit of a wordy response, but in the end this method is far more reliable than using SendKeys and focusing the window etc. You never need to lose focus of your own application.
If you have any questions, feel free to comment and I'll answer as best I can.
Cheers,
J
EDIT: Some references:
SendMessage function (MSDN)
EnumChildWindows function (MSDN)
Appending text using SendMessage
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.
I have an application which i want to run in the background. I want to get the executable name, for an example IExplorer.exe. I have played around with the following code:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
public static void Main()
{
int chars = 256;
StringBuilder buff = new StringBuilder(chars);
while (true)
{
// Obtain the handle of the active window.
IntPtr handle = GetForegroundWindow();
// Update the controls.
if (GetWindowText(handle, buff, chars) > 0)
{
Console.WriteLine(buff.ToString());
Console.WriteLine(handle.ToString());
}
Thread.Sleep(1000);
}
}
That only gets me the Window title, and the handle ID. I want to get the executable name (and maybe more information).
How do i achieve that?
I think you want "GetWindowModuleFileName()" instead of GetWindowText
You pass in the hwnd, so you'll still need the call to GetForegroundWindow()
A quick google search brings up an example such as C-Sharpcorner article