Get Word's window handle to use with WPF windows - ms-word

I have a number of WPF dialogs in my Word Add-In. For one of them (and only one, strangely), it is sometimes not focused when opened. I believe I need to set its parent.
I know there is a way to set the owner of a WPF window to a HWND, but is there any way to get a HWND in Word 2010? I found this HWND property but it is Word 2013 and later only. Is there any other way to get Word's HWND, other than using GetForegroundWindow() which does not guarantee the handle for the window I actually want (or any other similar kludge)?

I found something helpful in Get specific window handle using Office interop. But all those answers are based on getting the handle for a window you're newly creating. I modified it somewhat to get an existing window, and stuffed it into a utility method.
doc is the current document.
using System.Windows.Interop;
using System.Diagnostics;
public void SetOwner(System.Windows.Window pd)
{
var wordProcs = Process.GetProcessesByName("winword").ToList();
// in read-only mode, this would be e.g. "1.docx [Read-Only] - Microsoft Word"
var procs = wordProcs.Where(x =>
x.MainWindowTitle.StartsWith(Path.GetFileName(doc.FullName))
&&
x.MainWindowTitle.EndsWith("- Microsoft Word"));
if (procs.Count() >= 1)
{
// would prefer Word 2013's Window.HWND property for this
var handle = procs.First().MainWindowHandle;
WindowInteropHelper wih = new WindowInteropHelper(pd);
wih.Owner = handle;
}
}
Unfortunately it doesn't seem to be possible to account for multiple windows with the same document name (in different folders), because the number of processes is never greater than 1. But I think that's an acceptable limitation.

Related

The type or namespace name 'Forms' does not exist in the namespace 'System.Windows' FIX

Can someone please help me with this, am trying to use OpenFileDialog class from System.Windows.Forms to open a file dialog and read the selected file. Then, this error showed up. I've referenced it but still the same, below is the code.
`using UnityEngine
using UnityEngine.UI
using System.Windows.Forms;
public class OpenFileButtonScript : MonoBehaviour
{
public TextFieldScript textFieldScript;
public void OpenFile()
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";
openFileDialog.FilterIndex = 1;
openFileDialog.Multiselect = false;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string filePath = openFileDialog.FileName;
string text = System.IO.File.ReadAllText(filePath);
textFieldScript.inputField.text = text;
}
}
}`
It may look like you have access to all of the native Window system libraries, but it just looks like it. In actuality, a lot of the time you're simply given stubs, or shims, that look like the full Window libraries, because there's a certain element that Unity wants to use from those namespaces. If you think about it, the code you present above, what do you think it should do on Android or Nintendo devices? The simple answer is, it simply won't work.
Generally in cases like this, you have to gain access to the native operating system, and perform those calls directly. For example, there is a file browser asset on the Asset Store, that does this for you. It's not free, because the process isn't trivial.
Depending on how much effort you want to put in, you CAN read files from the local file stores (to varying degrees based on platform). It's possible to read the list of files in a location, and use either uGUI or UIToolkit to create your own File Open Dialogue box. Again, this isn't a trivial task either. So you have to be sure that you'd want to go down that path.

VsCode Extension custom CompletionItem disables built-in Intellisense

I am working on a VsCode extension in that I want to provide custom snippets for code completion.
I know about the option of using snippet json files directly, however those have the limitation of not being able to utilize the CompletionItemKind property that determines the icon next to the completion suggestion in the pop-up.
My issue:
If I implement a simple CompletionItemProvider like this:
context.subscriptions.push(
vscode.languages.registerCompletionItemProvider(
{scheme:"file",language:"MyLang"},
{
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
let item = new vscode.CompletionItem('test');
item.documentation = 'my test function';
item.kind = vscode.CompletionItemKind.Function;
return [item];
}
}
)
)
then the original VsCode IntelliSense text suggestions are not shown anymore, only my own. Should I just return a kind of an empty response, like
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
return [null|[]|undefined];
}
the suggestions appear again as they should. It seems to me that instead of merging the results of the built-in IntelliSense and my own provider, the built-in ones get simply overridden.
Question:
How can I keep the built-in IntelliSense suggestions while applying my own CompletionItems?
VsCode Version: v1.68.1 Ubuntu
I seem to have found the answer for my problem, so I will answer my question.
Multiple providers can be registered for a language. In that case providers are sorted
by their {#link languages.match score} and groups of equal score are sequentially asked for
completion items. The process stops when one or many providers of a group return a
result.
My provider seems to provide results that are just higher scored than those of IntelliSense.
Since I didn't provide any trigger characters, my CompletionItems were comteping directly with the words found by the built-in system by every single pressed key and won.My solution is to simply parse and register the words in my TextDocument myself and extend my provider results by them. I could probably just as well create and register a new CompletionItemProvider for them if I wanted to, however I decided to have a different structure for my project.

How to display modified body after Outlook ItemLoad

I have code to parse emails and add "tel:" links to phone numbers, but the modified email body doesn't get shown in the Outlook Reading Pane until the user manually reloads it (view another email, come back to this one).
I've tried a few hacks like Inspector.Display, and ActiveExplorer.ClearSelection ActiveExplorer.AddToSelection, but I can't get consistent results (Display will open new Inspectors for some users, very undesirable).
I was also going to investigate hooking the event sooner. Somehow accessing the email body before Outlook renders it, to avoid the need to refresh. I'm very new to VSTO, so I don't know what event would have access to the MailItem but happen after a user selects it and before it is rendered. I have thought about only processing new mail, but that doesn't help when I roll out this addin, only going forward.
Here is my current ItemLoad sub:
Private Sub Application_ItemLoad(Item As Object)
Dim myObj As Outlook.MailItem
Dim ob As Object
ob = GetCurrentItem()
If TypeOf ob Is Outlook.MailItem Then
myObj = ob
Dim oldbody As String = myObj.Body
If myObj.HTMLBody.Length > 0 Then
myObj.HTMLBody = RegularExpressions.Regex.Replace(myObj.HTMLBody, "(?<!tel:)(?<![2-9\.])(?<!\>\ )[+]?(1-)?(1)?[\(]?(?<p1>\d{3})[\)]?[\.\- ]?(?<p2>\d{3})[\.\- ]?(?<p3>\d{4})(?=[^\d])", " ${p1}-${p2}-${p3}")
Else
myObj.Body = RegularExpressions.Regex.Replace(myObj.Body, "(?<!tel:)(?<![2-9\.])[+]?(1-)?(1)?[\(]?(?<p1>\d{3})[\)]?[\.\- ]?(?<p2>\d{3})[\.\- ]?(?<p3>\d{4})(?=[^\d])", "tel:${p1}.${p2}.${p3}")
End If
myObj.Save()
refreshCurrentMessage()
End If
End Sub
GetCurrentItem() just returns either objApp.ActiveExplorer.Selection.Item(1) or objApp.ActiveInspector.CurrentItem based on TypeName(objApp.ActiveWindow)
Outlook doesn't reflect changes made through the OOM immediately. You need to switch to another folder/email to get the item refreshed because there is no way to update the item on the fly.
You can use the CurrentFolder property of the Explorer class which allows to set a Folder object that represents the current folder displayed in the explorer. Thus, the view will be switched to another folder. Then you can set the CurrentFolder folder to initial folder.
Also I'd suggest releasing all underlying COM objects instantly. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object.

How to find Window by variable title using TestStack.White framework?

I am using TestStack.White framework to automate opening new document in MS Word 2013.
I am opening Microsoft Word application with:
Application application = Application.Launch("winword.exe");
After that, I am trying to get the window by partial title:
Window window = application.GetWindow("Word", InitializeOption.NoCache);
But it throws an exception saying that there is no such window.
Window title is: Document1 - Word
The question is: How to get a window by partial title taking into consideration that the title is changing every time: "Document2 - Word", "Document3 - Word", etc.
Also tried *Word but looks like this func does not support wildcards
If I invoke:
List windows = application.GetWindows();
after launching an application, windows list is empty.
Thanks in advance,
Ostap
You can use EnumWindows to find all the open windows.
Within that callback you'll get a window handle which you can then us with GetWindowTextLength and GetWindowText
This will let you decide what window handle is to the window you want. From there you can use GetWindowThreadProcessId to retrieve the process ID for the word document.
And finally with that you can create a TestStack White application using the Application.Start()
It looks like opening window takes some noticeable time. GUI testing frameworks often have functions like Wait() to make sure the window is already created/visible/enabled. I'm not an expert in Teststack.White. Probably this document may help: http://teststackwhite.readthedocs.io/en/latest/AdvancedTopics/Waiting/
public static Window GetWindowBySubstring(this Application app, string titleSubString)
{
return app.GetWindows().FirstOrDefault(w => w.Title.Contains(titleSubString));
}

Hook word paste command

I have a Word 2007 VSTO addin for creating document templates. It allows you to add special content controls for cycles or conditions. Content controls are bound to custom xml part data (using content control ID as a reference).
I need to allow user to copy and paste CC. Word automatically change its ID so I lost the reference to custom xml part.
Is there any way to hook Word paste command and access the pasted range - Content Controls?
You can also use the Document.SelectionChange event on the VstoObject of the document, you can get it by using Microsoft.Office.Tools.Word.Document.GetVstoObject()
Example:
using WordTools = Microsoft.Office.Tools.Word;
WordTools.Document vstoDocument = Microsoft.Office.Tools.Word.Document.GetVstoObject(Globals.ThisAddIn.Application.ActiveDocument);
vstoDocument.SelectionChange += new WordTools.SelectionEventHandler(Document_SelectionChange);
private void Document_SelectionChange(object sender, WordTools.SelectionEventArgs e)
{
if (e.Selection.Range.Text != null)
{
// your code
}
}
I am not sure this is going to help you,
Wire up the event XMLSelectionChange in your project. This event has following parameters
(Selection Sel, XMLNode OldXMLNode, XMLNode NewXMLNode, ref int Reason)
Sel.Range should give the range which you are looking for.