Visual Studio 2015 在打字或在撕掉的编辑器之间移动时挂起
Visual Studio 2015 hangs while typing or moving between torn-off-editors
当我在使用 Visual Studio 2015 时输入 C# 文件时,它会间歇性地一次挂起长达 30 秒。这种情况是随机发生的,没有任何明确的原因(没有高 CPU,或者点击按钮后没有)。
当多个编辑器被撕掉后,windows之间的点击也需要很长时间。
一时兴起,我推测问题可能与 DDE / SendMessage(HWND_BROADCAST, …)
有关。快速测试程序确认发送到 HWND_BROADCAST
的消息将挂起呼叫者。
为了找出 window 的罪魁祸首,我在下面编写了测试程序 - 在我的例子中,它指向了 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;
}
}
}
当我在使用 Visual Studio 2015 时输入 C# 文件时,它会间歇性地一次挂起长达 30 秒。这种情况是随机发生的,没有任何明确的原因(没有高 CPU,或者点击按钮后没有)。
当多个编辑器被撕掉后,windows之间的点击也需要很长时间。
一时兴起,我推测问题可能与 DDE / SendMessage(HWND_BROADCAST, …)
有关。快速测试程序确认发送到 HWND_BROADCAST
的消息将挂起呼叫者。
为了找出 window 的罪魁祸首,我在下面编写了测试程序 - 在我的例子中,它指向了 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;
}
}
}