The issue:
We have an application written in C# that uses UIAutomation to get the current text (either selected or the word behind the carret) in other applications (Word, OpenOffice, Notepad, etc.).
All is working great on Windows 10, even up to 21H2, last update check done today.
But we had several clients informing us that the application is closing abruptly on Windows 11.
After some debugging I've seen some System.AccessViolationException thrown when trying to use the TextPatternRange.GetText() method:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
What we've tried so far:
Setting uiaccess=true in manifest and signing the app : as mentionned here https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/350ceab8-436b-4ef1-8512-3fee4b470c0a/problem-with-manifest-and-uiaccess-set-to-true?forum=windowsgeneraldevelopmentissues => no changes (app is in C:\Program Files\
In addition to the above, I did try to set the level to "requireAdministrator" in the manifest, no changes either
As I've seen that it may come from a bug in Windows 11 (https://forum.emclient.com/t/emclient-9-0-1317-0-up-to-9-0-1361-0-password-correction-crashes-the-app/79904), I tried to install the 22H2 Preview release, still no changes.
Reproductible example
In order to be able to isolate the issue (and check it was not something else in our app that was causing the exception) I quickly made the following test (based on : How to get selected text of currently focused window? validated answer)
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
var p = Process.GetProcessesByName("notepad").FirstOrDefault();
var root = AutomationElement.FromHandle(p.MainWindowHandle);
var documentControl = new
PropertyCondition(AutomationElement.ControlTypeProperty,
ControlType.Document);
var textPatternAvailable = new PropertyCondition(AutomationElement.IsTextPatternAvailableProperty, true);
var findControl = new AndCondition(documentControl, textPatternAvailable);
var targetDocument = root.FindFirst(TreeScope.Descendants, findControl);
var textPattern = targetDocument.GetCurrentPattern(TextPattern.Pattern) as TextPattern;
string text = "";
foreach (var selection in textPattern.GetSelection())
{
text += selection.GetText(255);
Console.WriteLine($"Selection: \"{selection.GetText(255)}\"");
}
lblFocusedProcess.Content = p.ProcessName;
lblSelectedText.Content = text;
}
When pressing a button, this method is called and the results displayed in labels.
The method uses UIAutomation to get the notepad process and extract the selected text.
This works well in Windows 10 with latest update, crashes immediately on Windows 11 with the AccessViolationException.
On Windows 10 it works even without the uiaccess=true setting in the manifest.
Questions/Next steps
Do anyone know/has a clue about what can cause this?
Is Windows 11 way more regarding towards UIAutomation?
On my side I'll probably open an issue by Microsoft.
And one track we might follow is getting an EV and sign the app itself and the installer as it'll also enhance the installation process, removing the big red warnings. But as this is an app distributed for free we had not done it as it was working without it.
I'll also continue testing with the reproductible code and update this question should anything new appear.
I posted the same question on MSDN forums and got this answer:
https://learn.microsoft.com/en-us/answers/questions/915789/uiautomation-throws-accessviolationexception-on-wi.html
Using IUIautomation instead of System.Windows.Automation works on Windows 11.
So I'm marking this as solved but if anyone has another idea or knows what happens you're welcome to comment!
I am trying to receive some video from a Parrot Bebop 2 drone.
I am using this Bebop.sdp file, which is supplied by Parrot.
I have previously tried in Python which worked by setting an environment variable OPENCV_FFMPEG_CAPTURE_OPTIONS to protocol_whitelist;file,rtp,udp.
This worked in Python.
Since then we have ported that project mostly to C#. But when trying to connect to the stream, we get this error Protocol 'rtp' not on whitelist 'file,crypto'!.
I have seen other examples where this -protocol_whitelist "file,rtp,udp" is passed through ffmpeg arguments, but in this case it does not seem as a solution, since i cannot pass it on.
Firstly i started with a simple test:
VideoCapture videoCapture = new VideoCapture(0);
var frame = videoCapture.QueryFrame();
while (frame != null)
{
using (frame)
{
CvInvoke.Imshow("frame", frame);
CvInvoke.WaitKey(1);
}
frame = videoCapture.QueryFrame();
}
This code get's the stream from the webcam and works.
I get the error when i run it with the SDP file:
VideoCapture videoCapture = new VideoCapture(#"./bebop.sdp");
var frame = videoCapture.QueryFrame();
while (frame != null)
{
using (frame)
{
CvInvoke.Imshow("frame", frame);
CvInvoke.WaitKey(1);
}
frame = videoCapture.QueryFrame();
}
I have tried to add both:
Environment.SetEnvironmentVariable("OPENCV_FFMPEG_CAPTURE_OPTIONS", "protocol_whitelist;file,rtp,udp");
And for a more aggressive approach:
Environment.SetEnvironmentVariable("OPENCV_FFMPEG_CAPTURE_OPTIONS", "protocol_whitelist;file,rtp,udp", EnvironmentVariableTarget.User);
None of them seem to have an impact since i get same error.
I would expect when setting the environment variables that the OpenCV would whitelist the protocols needed so the stream would come trough, and be displayed in the frame.
Environment variable was working, however due to the need for Visual Studio to restart first, in order to update environment variables, this was not discovered before today.
So I try to connect my c# WPF program to a BLE device and this is the code to connect to the device:
private async Task ConnectToWatcher(DeviceInformation deviceInfo) {
try {
// get the device
BluetoothLEDevice device = await BluetoothLEDevice.FromIdAsync(deviceInfo.Id);
// get the GATT service
Thread.Sleep(150);
var gattServicesResult = await device.GetGattServicesForUuidAsync(new Guid(RX_SERVICE_UUID));
service = gattServicesResult.Services[0];
// get the GATT characteristic
Thread.Sleep(150);
var gattCharacteristicsResult = await service.GetCharacteristicsForUuidAsync(new Guid(RX_CHAR_UUID));
characteristic = gattCharacteristicsResult.Characteristics[0];
// register for notifications
Thread.Sleep(150);
characteristic.ValueChanged += (sender, args) => {
Debug.WriteLine($"[{device.Name}] Received notification containing {args.CharacteristicValue.Length} bytes");
};
GattWriteResult result =
await characteristic.WriteClientCharacteristicConfigurationDescriptorWithResultAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
Debug.WriteLine($"Characteristics write result: status={result.Status}, protocolError={result.ProtocolError}");
} catch (Exception ex) when ((uint)ex.HResult == 0x800710df) {
Debug.WriteLine("bluetooth error 1");
// ERROR_DEVICE_NOT_AVAILABLE because the Bluetooth radio is not on.
}
}
The line
Debug.WriteLine($"Characteristics write result: status={result.Status}, protocolError={result.ProtocolError}"
creates the output
Characteristics write result: status=protocolError, protocolError=3
I couldn't find anywhere whats that supposed to mean. The effect is the Method characteristic.ValueChanged never gets called.
Do I have to do more to have the characteristic configurated? And has anybody any idea why the method isn't called or what that error message means?
Thanks a bunch.
Apparently, some Windows 10 builds have a COM security bug.
Solution was to register for Windows-Insider-Program and update Windows.
Update:
There are two more solutions to this:
1) Calling CoInitializeSecurity from outside your c#-code (didn't bring it to work)
- or-
2) Writing two new keys into the windows registry. You cann create a file "Bluetooth.reg", which will add those two keys on a doubleklick. This answer from https://social.msdn.microsoft.com/Forums/en-US/58da3fdb-a0e1-4161-8af3-778b6839f4e1/bluetooth-bluetoothledevicefromidasync-does-not-complete-on-10015063?forum=wdk was my solution:
Hi Kamen, I have experienced exactly same issue. You can give a quick try of the following:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID{C6BFD646-3DF0-4DE5-B7AF-5FFFACB844A5}]
"AccessPermission"=hex:01,00,04,80,9c,00,00,00,ac,00,00,00,00,00,00,00,14,00,\
00,00,02,00,88,00,06,00,00,00,00,00,14,00,07,00,00,00,01,01,00,00,00,00,00,\
05,0a,00,00,00,00,00,14,00,03,00,00,00,01,01,00,00,00,00,00,05,12,00,00,00,\
00,00,18,00,07,00,00,00,01,02,00,00,00,00,00,05,20,00,00,00,20,02,00,00,00,\
00,18,00,03,00,00,00,01,02,00,00,00,00,00,0f,02,00,00,00,01,00,00,00,00,00,\
14,00,03,00,00,00,01,01,00,00,00,00,00,05,13,00,00,00,00,00,14,00,03,00,00,\
00,01,01,00,00,00,00,00,05,14,00,00,00,01,02,00,00,00,00,00,05,20,00,00,00,\
20,02,00,00,01,02,00,00,00,00,00,05,20,00,00,00,20,02,00,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\YOURAPP.exe]
"AppID"="{C6BFD646-3DF0-4DE5-B7AF-5FFFACB844A5}"
Copy above content to a text file.
Replace 'YOURAPP.EXE' with your executable name
Optionally replace GUIDs (I have created a new one for you)
Save text file with an extension as .reg
Double click on the file.
You would see a message 'The Keys and values contained in ..... .reg have been successfully added to the registry.'
With this, I don't need to call CoInitializeSecurity from my app.
you need to call CoInitializeSecurity before
more info here. couple of weeks I spent looking for solution :)
https://social.msdn.microsoft.com/Forums/en-US/58da3fdb-a0e1-4161-8af3-778b6839f4e1/
Hopefully some of the experienced WPF developers have come across this issue before.
BACKGROUND: This information is probably not necessary to helping fixing the problem, but in case it is relevant.
My solution consists of three projects. A front-end GUI, a business logic service, and a printer service. The three projects have IPC via named pipes. The business logic hands the printing logic a label type and a pallet id.
The Problem: The printing logic then creates the label and prints it (by adding it to the print queue of a printer) As the title suggests this all works fine when I am debugging in visual studio. However when I deploy / install the services on my developer pc it is not working.
Update: It is not throwing an exception but I am only logging "About to send doc to printer" and not the line "Sent doc to printer" So it is hanging on the dw1.Write(fixedDoc); line
More Information: I am using .Net 4.0 in the printing project / visual studio 2013
public void printLabel(string labelType, string _palletID = null)
{
try
{
ILabelTemplate Label = createLabel(labelType, _palletID);
PrintDialog pd = new PrintDialog();
FixedDocument fixedDoc = new FixedDocument();
PageContent pageContent = new PageContent();
FixedPage fixedPage = getFixedPage();
fixedDoc.DocumentPaginator.PageSize = new System.Windows.Size(fixedPage.Width, fixedPage.Height);
IXamlTemplate vm = CreateViewModel(Label);
ILabelPrintDocument template = CreateTemplate(Label);
template.dockPanel.DataContext = vm;
template.dockPanel.Height = fixedPage.Height;
template.dockPanel.Width = fixedPage.Width;
template.dockPanel.UpdateLayout();
fixedPage.Children.Add(template.dockPanel);
((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
XpsDocumentWriter dw1 = PrintQueue.CreateXpsDocumentWriter(new System.Printing.PrintQueue(new System.Printing.PrintServer(), Label.PrinterName));
Library.WriteErrorLog("About to send doc to printer");
dw1.Write(fixedDoc);
Library.WriteErrorLog("Sent doc to printer");
}
catch (Exception ex)
{
Library.WriteErrorLog(ex);
}
SOLVED ... kind of
After several hours of trying different things and reading about this, I found that it was due to my application running as me when I'm debugging but as a LOCAL SYSTEM when I have it deployed. And a local system service does not have access to network resources such as printers. Despite learning this, I then started down the path of how to make a C# service print. Well after seeing many posts (too late in the game to be very helpful)
Like this and also this one I have learned that I was going down the wrong path.
The moral of the story is, if you're reading this post you're probably not at the level of "writing your own printing DLL using the Win32 API (in C/C++ for instance), then use it from your service with P/Invoke"
The solution that did work for me was instead of running this project as a service which was started via my GUI. I have instead turned it into a process which is still started and stopped via my GUI.
The code in question is
if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\yourAppNameGoesHere.exe"))
{
Process.Start(AppDomain.CurrentDomain.BaseDirectory + "\\yourAppNameGoesHere.exe");
}
then when the GUI is closed I run the code
if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\yourAppNameGoesHere.exe"))
{
Process[] myapps = Process.GetProcesses("yourAppNameGoesHere.exe");
foreach (Process _p in myapps)
{
_p.Kill();
}
}
Ok, so I followed the tutorial at unity3d.com (located here)
Just so that you dont have to or want to watch the whole video , here is the save/load functions.
//This one saves/creates the file
void OnDisable()
{
BinaryFormatter binFormatter = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/savedgame.dat");
GameData data = new GameData();
data.coinAmount = coinAmount;
data.upgradeLevel = upgradeLevel;
binFormatter.Serialize(file, data);
file.Close();
}
//And this one loads it
void OnEnable()
{
if (File.Exists(Application.persistentDataPath + "/savedgame.dat"))
{
BinaryFormatter binFormatter = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/savedgame.dat",FileMode.Open);
GameData data = (GameData)binFormatter.Deserialize(file) ;
file.Close();
coinAmount = data.coinAmount;
upgradeLevel = data.upgradeLevel;
}
}
I'm using OnDisable/OnEnable so that my game autosaves every time the users exits. This works on a pc and a mac, but when I build it to the Ipad air2 and its like nothing happens. Xcode trows a exception that says unknown filename(-1).
Thanks in advance for the help
Upon further investigation on android it turns out that the file gets created and the game reads data from it. The problems is here :
data.coinAmount = coinAmount;
data.upgradeLevel = upgradeLevel;
For some reason this does not write the correct data when the app runs on Android(probably the same for IOS).
When I supply a hard coded value i.e : data.coinAmount = 100; the game then reads it correctly.
Upon even further investigation turns out that the code work when you call Application.quit but does not work when we "force close" the app i.e using the ipads front button. Need help with this
Ok, so turns out when we stop a Unity game with the home button on a mobile device the methods OnEnable/OnDisable dont seem to we called or working properly. So my solution to the problem is to migrate the save code to the OnApplicationPause(bool pauseStatus) method. After a few tests this seems to be called every time you press the home screen, thus making sure that the game autosaves.
However this only fixed the issue on android devices. Someone please tells me what happens when a IOS user presses the home button so I can freakin save my game when that happens.
Fixed the issue. After some debugging it turns out that ios and .Net JIT do not like each other. This code fixes the issue:
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
System.Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
}
I recommend putting it in the Awake() method.