kevinmiles / dxcorecommunityplugins

Automatically exported from code.google.com/p/dxcorecommunityplugins
0 stars 0 forks source link

DevExpress.CodeRush.Common.DXCoreUnhandledException #147

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Message: Unhandled Exception was thrown.
Type: DevExpress.CodeRush.Common.DXCoreUnhandledException
Source: 
Target Site: 
Call Stack:
в DX_FormatOnSave.FormatOnSavePlugin.FormatDocument(Document doc) в
c:\dev\opensource\dx-formatonsave\DX_FormatOnSave\FormatOnSavePlugin.cs:стро
ка 166
в
DX_FormatOnSave.FormatOnSavePlugin.<>c__DisplayClass3.<DocumentSaving>b__2(O
bject state) в
c:\dev\opensource\dx-formatonsave\DX_FormatOnSave\FormatOnSavePlugin.cs:стро
ка 96
в System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate
callback, Object args, Int32 numArgs)
в MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source,
Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
в System.Windows.Threading.DispatcherOperation.InvokeImpl()
в
System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object
state)
в System.Threading.ExecutionContext.runTryCode(Object userData)
в
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedClea
nup(TryCode code, CleanupCode backoutCode, Object userData)
в System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext, ContextCallback callback, Object state)
в System.Threading.ExecutionContext.Run(ExecutionContext executionContext,
ContextCallback callback, Object state, Boolean ignoreSyncCtx)
в System.Threading.ExecutionContext.Run(ExecutionContext executionContext,
ContextCallback callback, Object state)
в System.Windows.Threading.DispatcherOperation.Invoke()
в System.Windows.Threading.Dispatcher.ProcessQueue()
в System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg,
IntPtr wParam, IntPtr lParam, Boolean& handled)
в MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr
lParam, Boolean& handled)
в MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
в System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate
callback, Object args, Int32 numArgs)
в MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source,
Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
в System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority
priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
в MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr
wParam, IntPtr lParam)
OS Version: Win32NT, 6.1.7601.65536
VS Version: 10.0, Ultimate
DXCore Version: 12.1.7.0
0 installed add-ins:

Original issue reported on code.google.com by AlexSkor...@gmail.com on 15 Oct 2012 at 8:21

GoogleCodeExporter commented 8 years ago

Original comment by RoryBec...@gmail.com on 15 Oct 2012 at 8:43

GoogleCodeExporter commented 8 years ago
Without knowing how to repro it, the best I can do is add a catch/log there, 
which I'll do.

Original comment by travis.illig on 25 Oct 2012 at 10:58

GoogleCodeExporter commented 8 years ago
It's throwing on a document activate call. That is...

var docToFormat; // method parameter
Document active = CodeRush.Documents.Active;
if(docToFormat != active)
{
  docToFormat.Activate();
}

Have to do that because I can only call CodeRush.Documents.Format() on an 
active document, which means basically that the format-on-save function is 
cycling through all the docs, making each one active, and doing the format.

I'm guessing this scenario was a "saving while the file is closing" thing. 
Like, hit the "Close" button, see the option to save, click OK, and a race 
condition happens where the doc is closed before it can be formatted.

Like I said, I can add the catch, but I'm not sure about how to truly fix it. I 
might need some help with that from someone more involved with DXCore... 
ALEX...? :)

Original comment by travis.illig on 25 Oct 2012 at 11:03

GoogleCodeExporter commented 8 years ago
OK, I added that catch/log block. I'll test it some more and post an update, 
but it'd be nice to know how I might be able to determine if the document is 
closing... and get to format it before the close finishes. I think that's 
beyond the scope of my abilities.

Original comment by travis.illig on 25 Oct 2012 at 11:13

GoogleCodeExporter commented 8 years ago
I think try/catch will work. To determine if the document is being closed, 
there's an event for this - EventNexus.DocumentClosing.

Original comment by AlexSkor...@gmail.com on 26 Oct 2012 at 8:40

GoogleCodeExporter commented 8 years ago
try/catch does catch it and it is when the user does a save-on-close.

I'm not sure how I'd actually fix that. I can't format a document unless it's 
made active but I can't make a closing document active (can I?). I guess it's 
an edge case I won't be able to handle.

Original comment by travis.illig on 26 Oct 2012 at 10:23

GoogleCodeExporter commented 8 years ago
Released version 2.0.2 of the extension which includes the try/catch/log. I 
still can't format a document that's closing, but at least it won't blow up.

Original comment by travis.illig on 26 Oct 2012 at 10:54

GoogleCodeExporter commented 8 years ago
Travis,
I don't think you should activate the document when it is closing. However, you 
may try formatting a document when it is just closed via a text buffer

      string documentFullName = textDocument.FullName;
      ITextBuffer textBuffer = CodeRush.TextBuffers[documentFullName];
      if (textBuffer == null)
        textBuffer = CodeRush.TextBuffers.Open(documentFullName);
      if (textBuffer != null)
        textBuffer.Format(textBuffer.Range);

Original comment by AlexSkor...@gmail.com on 29 Oct 2012 at 1:42

GoogleCodeExporter commented 8 years ago
Okay, that's something I didn't know you could do - I'll see if I can do that 
instead of what I'm doing now.

Original comment by travis.illig on 29 Oct 2012 at 10:34

GoogleCodeExporter commented 8 years ago
This is probably pretty dumb but... once I've formatted it like that (which 
works) how do I save the document back? CodeRush.TextBuffers doesn't have a 
Save option, ITextBuffer doesn't have a Save, and I don't see any static Save 
methods on any related classes.

Original comment by travis.illig on 29 Oct 2012 at 11:00

GoogleCodeExporter commented 8 years ago
I may have spoken too soon on this working at all. When the document is 
closing/closed, the document FullName property is null, so the text buffer 
never gets loaded. The private field _FullName has a value (I can see it in the 
debugger) but the property returns null, which I gather means the document 
itself has been otherwise removed from Visual Studio.

What that boils down to is, this:

if(textBuffer == null)
  textBuffer = CodeRush.TextBuffers.Open(documentFullName);

is effectively

if(textBuffer == null)
  textBuffer = CodeRush.TextBuffers.Open(null);

Or, with the Open call evaluated:

if(textBuffer == null)
  textBuffer = null;

So I can get around activating the document, it seems, but I still can't format 
a document when someone closes it unless I do some reflection spelunking to get 
the _FullName variable and then do some manual file saving using streams and 
the contents of the ITextBuffer.

Does that sound right?

Original comment by travis.illig on 29 Oct 2012 at 11:19

GoogleCodeExporter commented 8 years ago
Well... right or wrong, here's what I have working. Double-check me, if you 
would:

public static void FormatDocument(Document doc)
{
  if (doc == null)
  {
    throw new ArgumentNullException("doc");
  }

  bool isClosed = false;
  var docFullName = doc.FullName;
  if (docFullName == null)
  {
    // The document name will be null if the file is closed, but the
    // private instance property will still have the filename we need
    // to re-format.
    isClosed = true;
    docFullName = typeof(Document).GetField("_FullName", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic).GetValue(doc) as String;
  }
  var textBuffer = CodeRush.TextBuffers[docFullName];
  if (textBuffer == null)
  {
    // If the document has already closed, we can re-open it in the
    // background to format it.
    textBuffer = CodeRush.TextBuffers.Open(docFullName);
  }
  if (textBuffer != null)
  {
    var result = textBuffer.Format(textBuffer.Range);
    if (result == FormatResult.Success)
    {
      if (isClosed)
      {
        // If the document is closed, we have to manually save
        // it using an exclusive locking filestream. Without the
        // locking, VS may not have fully written the doc yet and we
        // end up in a race condition where the file contents
        // get all mangled.
        using (var stream = File.Open(docFullName, FileMode.Truncate, FileAccess.Write, FileShare.None))
        using (var writer = new StreamWriter(stream))
        {
          writer.Write(textBuffer.Text);
        }
      }
      else
      {
        // If the document is still active in VS, saving is way easier.
        doc.Save(docFullName);
      }
    }
  }
}

Original comment by travis.illig on 29 Oct 2012 at 11:45

GoogleCodeExporter commented 8 years ago
Travis,
What about the Path property of a TextDocument? Is it null as well? If not, I 
think you can use that instead.

To save the formatted text buffer, you may use the FileChange object as 
described in this article - 
http://www.skorkin.com/2011/07/how-to-automatically-edit-source-files-of-an-enti
re-visual-studio-solution-using-dxcore/

Original comment by devexpre...@gmail.com on 30 Oct 2012 at 3:54

GoogleCodeExporter commented 8 years ago
TextDocument.Path throws a NullReferenceException. I'm guessing the 
DocumentObject has already been nulled out since the doc is closing/closed from 
Visual Studio.

I'll have to check out the FileChange thing. Is that recommended over just 
writing to files using a stream as shown above? What's the benefit/difference?

Original comment by travis.illig on 30 Oct 2012 at 10:18

GoogleCodeExporter commented 8 years ago
One downside to FileChange - since I'm replacing the contents of the whole 
document (for each document that is being formatted) I lose the caret position. 
It jumps down to the end of the file. Document.Save doesn't lose the position, 
even with the formatting.

I suppose I could save/restore all the positions manually, but... eh. Unless 
there's some benefit to FileChange I don't know about, I will just stick with 
doc.Save for open docs and writing via streams for the closed docs.

Original comment by travis.illig on 30 Oct 2012 at 10:29

GoogleCodeExporter commented 8 years ago
One case I still can't handle - user saves the document while closing Visual 
Studio. My plugin doesn't seem to get the event.

That's SUPER edge case, though.

Original comment by travis.illig on 31 Oct 2012 at 12:40

GoogleCodeExporter commented 8 years ago
FileChange has the benefits when you do multiple edits of a single file. It 
will automatically sort, group and apply them to not break the structure of the 
code. If you replace the entire file, then there are now benefits.

Original comment by devexpre...@gmail.com on 31 Oct 2012 at 9:50

GoogleCodeExporter commented 8 years ago
When I close Visual Studio, I can't save the file. Furthermore, Visual Studio 
checks if there are unsaved files and suggests you to save them.

Original comment by devexpre...@gmail.com on 31 Oct 2012 at 9:52

GoogleCodeExporter commented 8 years ago
The last two comments are posted by me :-)

Original comment by AlexSkor...@gmail.com on 31 Oct 2012 at 9:54

GoogleCodeExporter commented 8 years ago
For now it appears I'm going to be unable to deal with save-on-close, but I 
posted a fix for everything else. I'll mark it closed for now; feel free to 
re-open if it breaks again. :)

Original comment by travis.illig on 31 Oct 2012 at 9:21

GoogleCodeExporter commented 8 years ago
Thank you for the fix, Travis!

Original comment by AlexSkor...@gmail.com on 1 Nov 2012 at 9:15