Issues with VNCSharpWpf for WPF in Microsoft Surface - c#

first of all, I have been learning Microsoft Surface for about 1-2 months now and my project requires me to look into incorporating the use of a VNC viewer into my Surface Application.
I have looked into VNCSharp and VNCSharpWpf from VNC control for WPF application and I'm currently using VNCSharpWpf as it has better user interaction in the WPF environment although the performance is somewhat lacking compared to the viewers out there.
Here is my question, is there any difference between Microsoft Surface WPF and the default WPF in how they handle framebuffer/threads ?
I noticed that when the client attempts to draw the rectangle in the Surface environment, it will cause an exception where by the rectangle to be updated has 0 width and height.
However, when I test it on the sample code the author of VNCSharpWPF provides (WPF on Window ), the error never occur.
I tried to workaround by setting and if clause to only draw if the width and height of the rectangle decoded is not 0. Although it prevents the application from crashing, it will results in dead pixel around the screen whenever there are changes in the screen in the server-end.
I've been stuck with this situation for 1-2 weeks already and have ran out of ideas and is in need of some guidance on where I should look into
Or is there is any cool VNC viewer/server out there that I can use for my Surface project that I've missed out ?

I've been having the same issue with VNCSharp WPF on a PC, and when tested VNC Sharp for WinForms, then it worked OK.
Furthermore, When I've tested VNCSharp for WPF on Debug, then it works OK, but failed on Release.
I've wasted several hours debugging it (I've learned some parts of the VNC protocol for that matter, since I've found out that it somehow reads the width and the height of the remote device from the wrong location in the netowrk stream).
The bug is related to floats comparison. It depends on the machine you have (it might work well on some machines and on others it might not)
Please look at VncClient, Line 349:
if (rfb.ServerVersion == 3.8) rfb.ReadSecurityFailureReason();
If you, while debugging, put a breakpoint there, you will see that rfb.ServerVersion is 3.8f
ServerVersion returns a calcualted float:
public float ServerVersion {
get {
return (float) verMajor + (verMinor * 0.1f);
}
}
You should expect that since ServerVersion is 3.8, then it will execute
ReadSecurityFailureReason which reads some extra bytes that are needed for the code to work, but on Release (Ctrl+F5, since in Visual Studio Release, while the code is being debugged, it will probably work OK) those extra bytes will not be read, so the width and height will be read from the wrong location on the stream, causing it to be 0px over 0px
For demontrating my point, please take the following code, and compile it as x86 (I'm assuming that you have an x64 machine and an x64 OS, since this is the situation here):
class Program
{
static void Main(string[] args)
{
SomeVersion someVersion = new SomeVersion(3, 8);
if (someVersion.Version == 3.8f)
{
Console.WriteLine("Version is 3.8");
}
Console.ReadLine();
}
}
public class SomeVersion
{
private int _major;
private int _minor;
public SomeVersion(int major, int minor)
{
_major = major;
_minor = minor;
}
public float Version
{
get
{
return (float)_major + (_minor * 0.1f);
}
}
}
Run the code in Debug x86 (both with visual studio debugger and with Ctrl+F5)
You should see that you get the message: "Version is 3.8" on both cases.
Now change it to Release x86... Run it with F5. You should get the message.
Now run it with Ctrl + F5... WTF??, no message!
In order to fix the bug in the Vnc Sharp WPF, I've took the class RfcProtocol, and added another function:
public bool CompareVersion(int major, int minor)
{
return major == verMajor && minor == verMinor;
}
Now on VNC Client (both line 188 and 349), I've changed the code so it will compare using the new function, instead of comparing 2 floats.

Related

UIAutomation throws AccessViolationException on Windows 11

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!

How to read text from 'simple' screenshot fast and effectively?

I'm working on a small personal application that should read some text (2 sentences at most) from a really simple Android screenshot. The text is always the same size, same font, and in approx. the same location. The background is very plain, usually a few shades of 1 color (think like bright orange fading into a little darker orange). I'm trying to figure out what would be the best way (and most importantly, the fastest way) to do this.
My first attempt involved the IronOcr C# library, and to be fair, it worked quite well! But I've noticed a few issues with it:
It's not 100% accurate
Despite having a community/trial version, it sometimes throws exceptions telling you to get a license
It takes ~400ms to read a ~600x300 pixel image, which in the case of my simple image, I consider to be rather long
As strange as it sounds, I have a feeling that libraries like IronOcr and Tesseract may just be too advanced for my needs. To improve speeds I have even written a piece of code to "treshold" my image first, making it completely black and white.
My current IronOcr settings look like this:
ImageReader = new AdvancedOcr()
{
CleanBackgroundNoise = false,
EnhanceContrast = false,
EnhanceResolution = false,
Strategy = AdvancedOcr.OcrStrategy.Fast,
ColorSpace = AdvancedOcr.OcrColorSpace.GrayScale,
DetectWhiteTextOnDarkBackgrounds = true,
InputImageType = AdvancedOcr.InputTypes.Snippet,
RotateAndStraighten = false,
ReadBarCodes = false,
ColorDepth = 1
};
And I could totally live with the results I've been getting using IronOcr, but the licensing exceptions ruin it. I also don't have $399 USD to spend on a private hobby project that won't even leave my own PC :(
But my main goal with this question is to find a better, faster or more efficient way to do this. It doesn't necessarily have to be an existing library, I'd be more than willing to make my own kind of letter-detection code that would work (only?) for screenshots like mine if someone can point me in the right direction.
I have researched about this topic and the best solution which I could find is Azure cognitive services. You can use Computer vision API to read text from an image. Here is the complete document.
How fast does it have to be?
If you are using C# I recommend the Google Cloud Vision API. You pay per request but the first 1000 per month are free (check pricing here). However, it does require a web request but I find it to be very quick
using Google.Cloud.Vision.V1;
using System;
namespace GoogleCloudSamples
{
public class QuickStart
{
public static void Main(string[] args)
{
// Instantiates a client
var client = ImageAnnotatorClient.Create();
// Load the image file into memory
var image = Image.FromFile("wakeupcat.jpg");
// Performs label detection on the image file
var response = client.DetectText(image);
foreach (var annotation in response)
{
if (annotation.Description != null)
Console.WriteLine(annotation.Description);
}
}
}
}
I find it works well for pictures and scanned documents so it should work perfectly for your situation. The SDK is also available in other languages too like Java, Python, and Node

Enforce program settings

I have made a small c# winforms program which among other stuff, prints barcodes. On some client machines where it operates, some other software for printing barcodes overrides my settings for printing the barcode and it resizes just the barcode.
If I change the code just for that machine, it either repositions the image (makes it smaller as well), or stretches it so wide that it cuts off one third of it. Currently I am only using the printing settings to set the margins to 0 and set the paper mode to landscape in the print dialog, and the image size is fixed in the printing process(I used constants). Below is the code for when the user clicks the print button, and also two constants defined outside of it.
const int barcodeX = 570;
const int barcodeY = 135;
private void Print_Click(object sender, EventArgs e)
{
DocPrint.DocumentName = "Document";
elements = 0;
PrintDialog.Document = DocumentDrucker;
DocPrint.DefaultPageSettings.Landscape = true;
DocPrint.DefaultPageSettings.Margins.Top = 0;
DocPrint.DefaultPageSettings.Margins.Left = 0;
DocPrint.DefaultPageSettings.Margins.Right = 0;
DocPrint.DefaultPageSettings.Margins.Bottom = 0;
//DocumentDrucker.OriginAtMargins = false;
if (PrintDialog.ShowDialog() == DialogResult.OK)
DocPrint.Print();
}
Also the lines to encode and print the barcode in the printing process. The barcodePoint is where the barcode is positioned, on the paper.
b.Encode(TYPE.CODE128A, "SBD" + currentItem.Text.Substring(0, 3) + currentItem.Text.Substring(4), Color.Black, Color.Transparent, barcodeX, barcodeY);
graphic.DrawImage(b.EncodedImage, barcodePoint);
The program runs fine under any other circumstances, so I have identified the problem, I just do not know how to go around the other software's settings. I have already reinstalled the drivers for the printer (no success), as well logged in as a different user on the same computer, and that made my program work. So it has something to do with the software installed on it, I just don't know what.
At first I thought it was a problem with the drivers and the OS, but I tried it on other computers and it worked fine as well. The problem persists just on the computers with the software.
Is there any way to make my program force it's printing settings for the barcode image, since the software installed on the machines always uses it's own settings? Or to make sure that the settings in my code will not be changed?
Uninstalling the software is not an option, as it is used for other processes.
EDIT: I have run the program from both my user logon (no software) and the target machine user (both on the same machine). The settings were identical in both cases, the only thing different was that on the target machine, the software was installed. What are some ways to make sure that my settings are enforced, instead of an X program overwriting them?

Bitmap.Save stops working after some hours

We have started facing an issue in the past months where the method System.Drawing.Bitmap.Save(string filename) stops working after the server has been running for several hours. The hours after which it starts failing are proportional to the server load.
This code involved with that call has been working perfectly well for several years, it gets and image from the user, resizes it and saves it to disk. The application is an ASP.Net application developed .Net Framework 3.5.
When the call to the Bitmap.Save fails, it raises the infamous exception:
ERROR MESSAGE: Error genérico en GDI+. STACK TRACE:
en System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
en System.Drawing.Image.Save(String filename, ImageFormat format)
en System.Drawing.Image.Save(String filename)
I've been reading a lot of posts about that exception, and I am fully aware that this exception is raised in many different situations. It is a generic exception that is raised for many different reasons (i.e when the application has no permisison to write to a folder, when the code is trying to save the image in the same file it is in reading from, etc) but none of those scenarios is our case.
When we realied the method was failing, we had just released a new version of our application, so we initially thought the error could be in our code (despite that part had not been changed, we thought we had changed something else that was interfering and producing the error), but the more we have investigated the less we understand when the error happens.
It is also important to mention that at the same time the error appeared, we also updated our servers with the latest windows updates, where I see also two suspicious ones:
KB2929755 http://support.microsoft.com/kb/2929755/en-us
Out of memory when you load some image resources in a Windows application
KB2957503 http://support.microsoft.com/kb/2957503/en-us
MS14-036: Description of the security update for Windows 7, Windows Server 2008 R2, Windows Server 2008, Windows Vista, and Windows Server 2003: June 10, 2014
This ones updates the GDIplus.dll on the server to avoid some security issues.
My feeling is that something on the server is not being released, like if some piece of code were leaking handlers or memory, and at some point the server runs out of them and can no longer save the Bitmap. When the error appears, any call to Bitmap.Save from any part of the application raises that exception. Rebooting the IIS solves the problem until the next time, however, that's not the case if we only restart the application pool.
If it can help in any way, we are using the HiQPdf library (version 6.8.0.0) to convert some HTML documents to PDF. This tool creates a new process for every conversion and killing it when finished, and supposedly releasing all the resources used in a proper way.
Is someone exeperiencing any similar issues?
Has someone had any issues with the Windows updates described?
I forgot to mention also that we tried resizing the images using WPF APIs, instead of GDI+ but we were facing the same problem, after several hours the server started raising an error (although this time the message was Excepción de HRESULT: 0x88982F8A), so we reverted it back to our original code.
Any help would be appreciated!
EDIT:
Actually, the code that peforms the image resizing and saving is the following. All variables are within using blocks, but for the casted image to a Bitmap, which I assume gets disposed anyway:
using (Image originalLogo = Image.FromStream(fuLogo.PostedFile.InputStream))
{
using (Image resizedLogo = ImageUtil.ResizeImage(originalLogo, maxWidth, maxHeight))
{
((System.Drawing.Bitmap)resizedLogo).Save(newFilePath);
}
}
Could the casting to Bitmap require creating an intermediate variable to force its dispose too, or that is not needed?
using (Image originalLogo = Image.FromStream(fuLogo.PostedFile.InputStream))
{
using (Image resizedLogo = ImageUtil.ResizeImage(originalLogo, maxWidth, maxHeight))
{
using (Bitmap bitmap=((System.Drawing.Bitmap)resizedLogo))
{
bitmap.Save(newFilePath);
}
}
}
Thanks,
Enric
EDIT:
I'm pasting below the code for the ResizeImage method:
public static System.Drawing.Image ResizeImage(System.Drawing.Image originalImage, int maxWidth, int maxHeight)
{
int imgWidth = originalImage.Width;
int imgHeight = originalImage.Height;
if (originalImage.Height<maxHeight && originalImage.Width<maxWidth) return originalImage;
double widhtRatio = ((double)maxWidth) / ((double)imgWidth);
double heightRatio = ((double)maxHeight) / ((double)imgHeight);
int targetWidth, targetHeight;
if (widhtRatio < heightRatio)
{
targetWidth = (int)(imgWidth * widhtRatio);
targetHeight = (int)(imgHeight * widhtRatio);
}
else
{
targetWidth = (int)(imgWidth * heightRatio);
targetHeight = (int)(imgHeight * heightRatio);
}
//Not all pixel formats are supported, therefore, using the
//originalImage pixel format raises an exception if the pixel format is not supported.
//By not specifying it, the Bitmap constructor will use one compatible with the FromImage method.
//For more info see: http://forums.asp.net/p/1195630/2066153.aspx
// Image resizedImage = new Bitmap(targetWidth, targetHeight, originalImage.PixelFormat);
System.Drawing.Image resizedImage = new Bitmap(targetWidth, targetHeight);
using (Graphics riGraphics = Graphics.FromImage(resizedImage))
{
riGraphics.CompositingQuality = CompositingQuality.HighQuality;
riGraphics.SmoothingMode = SmoothingMode.HighQuality;
Rectangle rectangle = new Rectangle(0, 0, targetWidth, targetHeight);
riGraphics.DrawImage(originalImage, rectangle);
riGraphics.Flush();
}
return resizedImage;
}
I've got an absolute stab in the dark for you:
In your application code, is the bitmap object wrapped in a using or explicitly disposed of after the Save() is called? I've seen hard to trace exceptions thrown from memory leaks in the past when dealing with IDisposible objects when they're used in repetition and don't get properly disposed of. These circumstances always seemed to be intermittent like what you're describing and took tons of digging before realizing the solution was as simple as calling Bitmap.Dispose() (or putting it back after having it accidentally deleted during a re-factor or code update).
However unlikely, because it sounds like your code worked before having windows updates applied...I thought I'd throw that out there.

C# Program Only Works in Debug Mode

Me and some of my colleagues are working on a project together, and have encountered a weird issue we can't manage to fix.The project involves the creation of a VNC connection between a client and a server, and is written in C# (we're using Visual Studio 2010). We're using the VNCSharp library for the client.The issue I speak of is that once we start the connection with the server, an ArgumentException is thrown.
Some of the information supplied was this:
********** Exception Text **********
System.ArgumentException: Parameter is not valid.
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
at VncSharp.RemoteDesktop.SetupDesktop()
at VncSharp.RemoteDesktop.Initialize()
at VncSharp.RemoteDesktop.Connect(String host, Int32 display, Boolean viewOnly, Boolean scaled)
at VncSharp.RemoteDesktop.Connect(String host)
at RemoteDesktopTest.Form2.startConnection()
Another weird thing about this is that it only occures some of the times, whereas in others it works perfectly well. Specifically, it always works when run in debug mode (i.e, when we run the program line-by-line using F11), and either works or doesn't work when run regularly (i.e Ctrl+F5), without any pattern we could recognize.
We would be really grateful for any and all help; if there are any details I can add that would assist in the answering of this question, please let me know.
Additionally, I apologize for any grammar/spelling mistakes; English is not my first language... and I also apologize if something about this question is not alright. We're all beginners and this is our first "big project", so this is also my first time asking a question in Stack Overflow.
EDIT:
There are some parts of the code that are potentially relevant.
These are the lines of code automatically generated after we added the VncSharp control to the form and customized its settings:
this.remoteDesktop1 = new VncSharp.RemoteDesktop();
this.remoteDesktop1.AutoScroll = true;
this.remoteDesktop1.AutoScrollMinSize = new System.Drawing.Size(608, 427);
this.remoteDesktop1.Dock = System.Windows.Forms.DockStyle.Fill;
this.remoteDesktop1.Location = new System.Drawing.Point(0, 0);
this.remoteDesktop1.Name = "remoteDesktop1";
this.remoteDesktop1.Size = new System.Drawing.Size(1113, 580);
this.remoteDesktop1.TabIndex = 1;
This is the line of code in which I call the Connect method, while IP is simply the string taken from a text box:
remoteDesktop1.Connect(this.IP);
These are from the method which handles the ConnectComplete event (e is the EventArgs object passed to the method):
this.Location = new Point(0,0);
this.Size = Screen.PrimaryScreen.WorkingArea.Size;
this.remoteDesktop1.Size = new System.Drawing.Size(e.DesktopWidth, e.DesktopHeight);
Aside from the line in which the Disconnect method is called, we've written literally no other lines of code that deal with this object. If I'll realize I'd forgotten something, I'll edit again and add it. Also, if there's anything specific in the code I should add here, please let me know.
The issue was related to timing, it seems.
Out of debug mode, the program ran too fast and those width and height variable didn't have their values updated.
Luckily, VncSharp is open source, so I could add my own line and leave it in a loop as long as either of those two variables still has its default value, and now it works.
Thanks for the help, everyone :)
Had the same problem. For me it worked to compile the vncsharp solution in debug mode.
In RfbProtocol line 398 (first line of the ReadServerInit method), I transformed
int w = Reader.ReadUInt16();
to
int w = 0;
while (w == 0)
w = Reader.ReadUInt16();

Categories