.NET: drawing text hangs - FormattedText bug? - c#

A customer has reported that our software hangs when he runs it on one of his computers. We narrowed down the problem to rendering text with FormattedText and put together a simple application for him to try, which just renders some text with different font parameters - this would hang too.
Here's the bit of code which does the actual text drawing:
Typeface typeface = new Typeface(m_Font, m_FontStyle, m_FontWeight, FontStretches.Normal);
FormattedText ftext = new FormattedText(m_Text, new CultureInfo("en-US"), FlowDirection.LeftToRight, typeface, m_FontSize, m_FontColor);
ftext.TextAlignment = CenterText ? TextAlignment.Center : TextAlignment.Left;
if (m_DrawOutline)
{
Geometry geom = ftext.BuildGeometry(CenterText ? new Point(ftext.Width, 0) : new Point());
dc.DrawGeometry(m_FontColor, DrawOutline ? new Pen(m_OutlineColor, m_OutlineWidth) : null, geom);
}
else
dc.DrawText(ftext, CenterText ? new Point(ftext.Width, 0) : new Point());
The program simply stops responding whenever the ftext.BuildGeometry, dx.DrawText methods or the ftext.Width property is called, regardless of font and text parameters used. This only happens on one computer, which is a touchscreen laptop (not sure this is relevant) running Windows 7. We already tried reinstalling the .NET Framework but this didn't help.
Has anyone encountered a similar problem? Any ideas how to fix, work around or at least find out more about what the reason for this problem is?
Thanks.

Never personally encountered that problem and I use Windows 7 at home. However, if it is only on one machine, it is a safe bet that the problem is not software related. The first step I would try is to download the most recent video display drivers and installing them. If it is still giving you a problem, try booting into safe mode and see if it will run.

I've had this problem occur due to a corrupt presentation font cache.
Stop the font cache service, delete the file %systemdrive%\Documents and Settings\LocalService\Local Settings\Application Data\FontCache3.0.0.0.dat (xp) and restart.
Details at http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/7cc032c1-5f4d-4518-adc6-f53afd051e6b

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!

WPF Printing (XpsDocumentWriter) working in debug but not in deployment

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();
}
}

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();

Fellow Oak DICOM - changing image window level

I am not an experienced programmer, just need to add a DICOM viewer to my VS2010 project. I can display the image in Windows Forms, however can't figure out how to change the window center and width. Here is my script:
DicomImage image = new DicomImage(_filename);
int maxV = image.NumberOfFrames;
sbSlice.Maximum = maxV - 1;
image.WindowCenter = 7.0;
double wc = image.WindowCenter;
double ww = image.WindowWidth;
Image result = image.RenderImage(0);
DisplayImage(result);
It did not work. I don't know if this is the right approach.
The DicomImage class was not created with the intention of it being used to implement an image viewer. It was created to render preview images in the DICOM Dump utility and to test the image compression/decompression codecs. Maybe it was a mistake to include it in the library at all?
It is difficult for me to find fault in the code as being buggy when it is being used for something far beyond its intended functionality.
That said, I have taken some time to modify the code so that the WindowCenter/WindowWidth properties apply to the rendered image. You can find these modifications in the Git repo.
var img = new DicomImage(fileName);
img.WindowCenter = 2048.0;
img.WindowWidth = 4096.0;
DisplayImage(img.RenderImage(0));
I looked at the code and it looked extremely buggy. https://github.com/rcd/fo-dicom/blob/master/DICOM/Imaging/DicomImage.cs
In the current buggy implementation setting the WindowCenter or WindowWidth properties has no effect unless Dataset.Get(DicomTag.PhotometricInterpretation) is either Monochrome1 or Monochrome2 during Load(). This is already ridiculous, but it still cannot be used because the _renderOptions variable is only set in a single place and is immediately used for the _pipeline creation (not giving you chance to change it using the WindowCenter property). Your only chance is the grayscale _renderOptions initialization: _renderOptions = GrayscaleRenderOptions.FromDataset(Dataset);.
The current solution: Your dataset should have
DicomTag.WindowCenter set appropriately
DicomTag.WindowWidth != 0.0
DicomTag.PhotometricInterpretation == Monochrome1 or Monochrome2
The following code accomplishes that:
DicomDataset dataset = DicomFile.Open(fileName).Dataset;
//dataset.Set(DicomTag.WindowWidth, 200.0); //the WindowWidth must be non-zero
dataset.Add(DicomTag.WindowCenter, "100.0");
//dataset.Add(DicomTag.PhotometricInterpretation, "MONOCHROME1"); //ValueRepresentations tag is broken
dataset.Add(new DicomCodeString(DicomTag.PhotometricInterpretation, "MONOCHROME1"));
DicomImage image = new DicomImage(dataset);
image.RenderImage();
The best solution: Wait while this buggy library is fixed.

Documents.Close makes Word visible

I have been trying a workaround for this, for quite a long time, but haven't found one yet.
On calling Documents.Close(), Word, which was opened with visible = false, becomes visible.
This is my close statement (document is already saved so no need to save again):
WordApp.Documents.Close(Word.WdSaveOptions.wdDoNotSaveChanges,
Word.WdOriginalFormat.wdOriginalDocumentFormat);
You could just call WordApp.Quit().
Office apps still follow the MDI approach: You run 1 App and in that app you can open 1 or more documents.
It's easy to lose track of that App in the background as we usually only open one document. But there are two levels of Close here.
You could also explicitly set WordApp.Visible = false immediately after the operation; this might cause a brief flash, but should set the application back to invisible.
To avoid the brief flash of visibility, sometimes using the WordApp.ScreenUpdating property as well can help. Set it to false before attempting the Documents.Close() call, then reset to true after that's complete.
The accepted solution (calling WordApp.Quit()) was not a viable option for me. I tried setting
WordApp.ScreenUpdating = false
immediately prior to calling Documents.Close() and that did not help either - I still got the screen flash.
I then tried setting
WordApp.ActiveWindow.Visible = false
immediately after opening the document. That did not make any difference either.
Finally I tried setting
WordApp.ActiveWindow.Top = -5000
(so as to move the window display well out of the visible desktop area in my monitor setup - if you have an unusual (giant!) monitor setup that might not work for you, adjust accordingly) and that solved the problem - no more flashing.
An annoying hack, but worked in my case.
None of above comments work for me. I tried with:
WordApp.ActiveWindow.Top = -5000
But my program terminates with "active window is maximized" exception.
I ultimately resolved it by following call before invoke Document.Close():
m_word.ActiveWindow.WindowState = WdWindowState.wdWindowStateMinimize;
It's a perfect solution for me. Hope it would work for you as well.
Using the ActiveDocument.Close() method will not show the window.
WordApp.ActiveDocument.Close(saveChanges: false);
None of the above solutions worked for me.
I finally realized that for me it was the AutoOpen macro that was the problem. Every time a Word document was opened, AutoOpen would make the ActiveDocument.Visible = False, run some changes (like opening the style pane), then turn ActiveDocument.Visible = True at the end.
This final line in AutoOpen is what caused every document to briefly flash on the screen. Removing both ActiveDocument.Visible = False and ActiveDocument.Visible = True from the AutoOpen macro solved the issue.

Categories