在断开编辑器之间键入或移动时,Visual Studio 2015会挂起

时间:2018-08-05 21:17:20

标签: visual-studio visual-studio-2015

当我在使用Visual Studio 2015时键入C#文件时,它会间歇性地挂起一次,最多可持续30秒。这种情况是随机发生的,没有明确的原因(没有高CPU使用率,或者没有在单击按钮后出现)。

当多个编辑器被撕下时,在窗口之间单击也需要很长时间。

1 个答案:

答案 0 :(得分:1)

总的来说,我认为问题可能与DDE / SendMessage(HWND_BROADCAST, …)有关。快速测试程序确认,发送到HWND_BROADCAST的消息将使呼叫者挂掉。

要弄清楚罪魁祸首是什么,我在下面编写了测试程序-在我的情况下,该程序将手指指向OfficeC2RClient。终止OfficeC2RClient进程可以解决此问题。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SendMessageTest
{
    class Program
    {
        private static readonly IntPtr
            HWND_BROADCAST = (IntPtr)65535;
        private const int
            WM_NULL = 0;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessageTimeout(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam, int fuFlags, int uTimeout, out IntPtr result);

        protected delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        protected static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);

        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        protected static extern int GetWindowTextLength(IntPtr hWnd);

        [DllImport("user32.dll")]
        protected static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);

        [DllImport("user32.dll")]
        protected static extern bool IsWindowVisible(IntPtr hWnd);

        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int processId);

        protected static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
        {
            int size = GetWindowTextLength(hWnd);
            if (size++ > 0 && IsWindowVisible(hWnd))
            {
                StringBuilder sb = new StringBuilder(size);
                GetWindowText(hWnd, sb, size);
                Console.WriteLine(sb.ToString());
            }
            return true;
        }

        static void Main(string[] args)
        {
            LoopSendMessage();
        }

        private static void BroadcastMessage()
        {
            while (true)
            {
                var stp = Stopwatch.StartNew();
                SendMessage(HWND_BROADCAST, WM_NULL, IntPtr.Zero, IntPtr.Zero);
                stp.Stop();
                Console.WriteLine("Duration = {0}", stp.Elapsed);

                if (stp.ElapsedMilliseconds > 250)
                {
                    Debugger.Break();
                }

                Thread.Sleep(100);
            }
        }

        private static void LoopSendMessage()
        {
            if (EnumWindows(LoopSendMessage_Call, IntPtr.Zero))
            {
                Console.WriteLine("Completed");
            }
            else
            {
                Console.WriteLine("Failed");
            }
            Console.ReadLine();
        }

        private static bool LoopSendMessage_Call(IntPtr hWnd, IntPtr lParam)
        {
            IntPtr _unused;
            var stp = Stopwatch.StartNew();
            if (SendMessageTimeout(hWnd, WM_NULL, IntPtr.Zero, IntPtr.Zero, 1, 5000, out _unused) == IntPtr.Zero)
            {
                if (stp.ElapsedMilliseconds > 5)
                {
                    if (Marshal.GetLastWin32Error() == 1460)
                    {
                        Console.WriteLine($"HWND {hWnd.ToString("x8")} timed out after {stp.ElapsedMilliseconds:n0}ms");
                    }
                    else
                    {
                        Console.WriteLine($"HWND {hWnd.ToString("x8")} failed after {stp.ElapsedMilliseconds:n0}ms");
                    }

                    int pid;
                    GetWindowThreadProcessId(hWnd, out pid);
                    var proc = Process.GetProcessById(pid);
                    Console.WriteLine($"    {proc.Id} {proc.ProcessName}");
                }
            }
            else if (stp.ElapsedMilliseconds > 250)
            {
                Console.WriteLine($"HWND {hWnd.ToString("x8")} took {stp.ElapsedMilliseconds:n0}ms");
            }
            return true;
        }
    }
}