I'm dealing with a windows forms .NET application written in C# which needs to display a 3D pdf with all the associated features (rotate the object, change lights and so on). I'm using the AxAcroPDF COM control and it run smoothly. The problem is that when I try to close the form where the control is placed, sometimes it hangs for several seconds with no apparent reason while disposing the control. The 3D file I loaded during the tests is not particulary heavy. The very same file in the standalone adobe reader opens and closes with no particular delay.
I'm using the following code within the windows form closing event:
private void DrawingForm_FormClosing(object sender, FormClosingEventArgs e)
{
this.axAcroPDF.Dispose();
Application.DoEvents();
CoFreeUnusedLibraries(); }
[System.Runtime.InteropServices.DllImport("ole32.dll")]
static extern void CoFreeUnusedLibraries();
The interesting thing is that the form closes normally if the file is just displayed, but, when the object within the 3D file is rotated, it hangs during closing. When it hangs, the icon of a watch (the same shown in standalone Adobe PDF) is displayed. The hanging time is between 15-20 seconds.
I tried to display the file within the webbrowser control but I got similar results. What can be the cause of this problem?
I tried to search for alternative stable controls but I haven't found any with 3D support.
In FormClosing event handler add 2 lines:
this.Controls.Remove(yourAxAcroPDFControl);
yourAxAcroPDFControl = null;
Consider it a temporary solution until Adobe has an update. I checked Adobe SDK samples and those cause problems too, despite being written by Adobe themselves so we could expect them to consider it a problem.
This is how I fixed it - not great but it works!
protected override void WndProc(ref System.Windows.Forms.Message m)
{
// WM_CLOSE = 16
if (16 == m.Msg)
{
//closing
axAcroPDF1.LoadFile("UNLOAD_FILE_FOR_FUDGE");
// we need to wait a bit
System.Threading.Thread.Sleep(500);
}
base.WndProc(ref m);
}
The solution to the problem is not to call Dispose() but to let the operating system taking care of this instead. I tried and it works perfectly. Why? Maybe .NET calls crossing the COM boundaries cause the operation to slow down?
Related
My application has ATL-based GUI (CWnd, CDialog,...) and it consists of multiple pages (CDialog). One of these pages is otherwise empty but it has a placeholder frame (CWnd) that resizes with the dialog. Everything is built as x64.
When the page loads, it asks for a control handle from managed (C#) side of the application using COM-interop, and adds the control to the dialog as CWnd that is created from that handle:
Managed implementation simplified:
// Class "ManagedControlProvider"
private Control myUserControl;
public long CreateControl()
{
myUserControl = /*Create some new inheritant of UserControl */
myUserControl.Dock = DockStyle.Fill;
return myUserControl.Handle.ToInt64();
}
Native side simplified:
// Call the managed class. Lifetime of m_pManagedControlProvider
// is ensured elsewhere.
LONGLONG lHandle = m_pManagedControlProvider->CreateControl();
// m_pUserCtrlAsCWnd is CWnd*
m_pUserCtrlAsCWnd = CWnd::FromHandle((HWND)lHandle);
m_pUserCtrlAsCWnd->SetParent(this);
// m_ControlFrame is just a native helper-CWnd the dialog that
// resizes with it a so gives us the size we want to set for the
// managed control. This code is also call in every resize -event.
RECT winRect;
m_ControlFrame.GetWindowRect(&winRect);
ScreenToClient(&winRect);
m_pUserCtrlAsCWnd->SetWindowPos(NULL,
winRect.left, winRect.top, winRect.right - winRect.left,
winRect.bottom - winRect.top, 0);
I have done this multiple times and it usually works exactly as is should. But sometimes, like now, I'm experiencing application hangs without any clear reason. With my current control this seems to happen roughly 5s after the focus is set to some other desktop application.
I have verified that the issue is not in the managed control's lifetime or GC. Also it's reproducible in debug build so optimizations are not to blame. When the hang occurs, I can attach debugger and see that some ATL loop keeps on going but that's the only piece of code I'm able to see in stack (imo this indicates that the message loop is somehow caught in infinite loop without interacting with my code).
Now for the dirties fix ever: I added a separate thread to my managed control that invokes this.Focus() every second on the UI thread. Obviously this is a ridiculous hack but it works as long as I pause the focusing everytime user opens combos etc (otherwise they get closed every second).
What am I doing wrong or what could cause this somewhat unpredictable behavior?
I don't know why or what it has to do with anything, but the application hang somehow originated from WM_ACTIVATE. So the solution was to override WINPROC at the main CDialog and block forwarding of that message. Everything has been working without any issues since then.
I'll not mark this as answer because I don't know why this solution works.
I have a simple wpf application. But it is using CefSharp to open some links in chrome based browser. I found that once the main window of the application is closed, It is closed from the UI but it still runs in the background.
I tried adding additional code to force close it. but no hope. I think some components of cefsharp is not ending correctly. but not exactly sure on what is going wrong.
Used the below code and some other snippets too
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
foreach (Window w in App.Current.Windows)
{
if (w.DataContext != this)
w.Close();
}
Application.Current.Shutdown();
}
As I said in my comment, try: Environment.Exit(0);
If that doesn't work, start with Cef.Shutdown();
https://stackoverflow.com/a/9050477/1274820
If you REALLY need it to close out you can also use Environment.Exit() but it is not graceful at all (more like ending the process).
I use StatusStrip that contains ToolStripStatusLabel. OS - Windows 7, framework 2.0.
Usually all displayed normal, but sometimes ToolStripStatusLabel looks like black box:
I read that windows bug, but how I can fix it?
This is an obscure bug, triggered when you display the form with the Windows toolbar overlapping your StatusStrip. Moving the window away from the toolbar doesn't get the ToolStripItems on the status strip repainted properly. You'll find a bit of background in this forum post. There was a weak promise for a future fix for it, no idea if that ever happened. Probably not if you are running this on Win7.
You'll need to pay more attention to the position of the window, making sure that parts of it don't disappear underneath the toolbar. In general something you'd always consider, extra important as long as this bug doesn't get fixed. If you don't want to nail down the startup position (you ought to, users tend to like a window getting redisplayed where they last moved it) then simply change the form's StartPosition property to "CenterScreen".
This bug has never been fixed. It was in framework 2 and is still in framework 4.
The answer from Hans is a copy of the answer in social.msdn.microsoft.com.
But it is not helpful for me because "CenterScreen" does not solve the problem.
The cause of the problem is not the Windows Taskbar. The cause is a bug that does not draw the StatusStrip when the main Form is behind ANY other window at the first moment of drawing the StatusStrip. But this will also happen when you start the new process with Process.Start() from another process and the new process opens behind the window of another process.
I found a much better solution than the one proposed by Microsoft.
First I tried with
statusStrip.Invalidate();
but it does not work. So we need a stronger way to force Windows to redraw the StatusStrip. Important: The redrawing must happen when the Form with the StatusStrip is ALREADY in foreground! This is so easy that I don't understand why Microsoft does not suggest this method.
Timer mi_StatusTimer = new Timer();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
mi_StatusTimer.Interval = 500;
mi_StatusTimer.Tick += new EventHandler(OnTimerBugFix);
}
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
mi_StatusTimer.Start();
}
void OnTimerBugFix(object sender, EventArgs e)
{
mi_StatusTimer.Stop();
statusStrip.Hide();
Application.DoEvents();
statusStrip.Show();
}
I'm writing a GIS application in C#. A portion of the application allows the user to select a KML file, and then the program will process that file. I'm using an OpenFileDialog, but the problem is that all of the code is executed before the dialog gets closed (and after the user has OK'd the file). It takes quite awhile because the program has to zoom and do other things. Is there a way to close the dialog programmatically before my code is executed?
EDIT: Some code for those who ask.
private void OnKMLFileSet(object sender, CancelEventArgs e)
{
Polygon polygon = KmlToPolygon(openFileDialog2.FileName);
// After this, I no longer need the file, but the dialog stays open until the end of the method
Graphic graphic = new Graphic();
graphic.Geometry = polygon;
textBox1.Text = string.Format("{0:n}", CalculateAreaInSqKilometers(polygon)).Split('.')[0];
textBox2.Text = string.Format("{0:n}", CalculateAreaInSqMiles(polygon)).Split('.')[0];
textBox3.Text = string.Format("{0:n}", CalculateAreaInSqKnots(polygon)).Split('.')[0];
Note polyInfo = new Note("Polygon with nautical area: " + textBox3.Text, polygon);
map.Map.ChildItems.Add(polyInfo);
map.ZoomTo(polygon.GetEnvelope());
}
It sounds like the dialog is actually closed, but it's still "visible" because the main window is busy and hasn't repainted itself yet.
Some ideas:
The easy way: call the Refresh() method on the main form where the dialog is still visible. Always call it immediately after ShowDialog returns.
If loading takes quite a bit of time, it might be desirable to create a pop-up "loading" dialog, possibly with a cancel button. Use the BackgroundWorker class to load the file in a background thread. When the worker is done, the file is loaded and the pop-up window can be closed. Remember not to change anything in the user interface from the background thread without proper synchronization.
EDIT: After looking at the code, I think I see your problem. You're handling the FileOk event. This will have the effect you are trying to avoid. Use the dialog like this:
if (openFileDialog1.ShowDialog() == DialogResult.OK) {
// open file
}
Don't use the FileOk event. I've never had reason to use it before... Also it might be helpful to follow the advice I already gave.
Sometimes when our application launches it flashes orange in the taskbar. I don't think we explicitly wrote any code to do this but it still happens. Our program is a c# winforms app that sometimes takes a while to load. Any ideas what could be causing this and how I can prevent it?
I believe you can use MSDN's flashwinfo .
Edit - Here's some more info .
From my experience, if the application isn't the current application the user is using, but does something 'on its own' to update the UI(?) the system recognizes this and notifies the user by the orange flash thing.
So if your application is doing some long processing and the user clicks away to another application/window, they probably will get the orange flash.
A possible alternative would be to prevent the application from showing in the Taskbar until loading has completed.
So, something along the lines of:
// prevent from showing in the constructor (or via the designer)
public MyAppMainForm()
{
this.ShowInTaskbar = false;
// other initialization
}
// now you're ready to show in the Taskbar
private void MyAppMainForm_Load(object sender, EventArgs e)
{
this.ShowInTaskbar = true;
}