You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#调用CAD SDK/DLL遇CAD无响应,如何实现超时检测?

这个问题我之前做CAD插件开发时也碰到过,核心痛点就是同步调用CAD的阻塞API会把你的应用也拖进无响应状态。下面给你几个可行的解决思路,结合C#的特性来实现超时控制和状态探测:

解决方案1:异步调用+超时终止

把CAD接口的调用放到独立任务中,结合Task.WhenAny和CancellationToken来实现超时控制。这样即使CAD卡住,你的应用也能在指定时间后恢复响应。

代码示例(通用异步版)

public async Task<string> GetCadFileNameWithTimeout(int timeoutMs)
{
    using var cancellationTokenSource = new CancellationTokenSource(timeoutMs);
    
    try
    {
        // 将CAD接口调用包装到后台任务中
        var getFileNameTask = Task.Run(() =>
        {
            // 替换成你实际的CAD API调用,比如:
            // return YourCadSdk.ActiveDocument.FileName;
            return "SampleDrawing.dwg"; // 示例返回值
        }, cancellationTokenSource.Token);

        // 等待任务完成或超时
        var completedTask = await Task.WhenAny(getFileNameTask, Task.Delay(Timeout.Infinite, cancellationTokenSource.Token));

        if (completedTask == getFileNameTask)
        {
            // 任务正常完成,返回结果
            return await getFileNameTask;
        }
        else
        {
            throw new TimeoutException($"获取CAD文件名超时(超过{timeoutMs}毫秒)");
        }
    }
    catch (OperationCanceledException)
    {
        throw new TimeoutException($"获取CAD文件名超时(超过{timeoutMs}毫秒)");
    }
}

针对CAD UI线程绑定的特殊情况

很多CAD SDK(比如AutoCAD)的API要求在其主线程执行,不能随便用后台线程。这种情况下可以用WinForms/WPF的Invoke机制带超时:

WinForms版本

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

public string GetCadFileNameWithTimeoutWinForms(int timeoutMs)
{
    string fileName = null;
    bool isCompleted = false;

    // 定义要在CAD主线程执行的委托
    Action getFileNameAction = () =>
    {
        fileName = YourCadSdk.ActiveDocument.FileName;
        isCompleted = true;
    };

    // 获取CAD的主窗口句柄(根据你的CAD软件调整获取方式)
    IntPtr cadWindowHandle = GetForegroundWindow();
    var cadControl = Control.FromHandle(cadWindowHandle);

    // 异步Invoke并等待超时
    var asyncResult = cadControl.BeginInvoke(getFileNameAction);
    if (!asyncResult.AsyncWaitHandle.WaitOne(timeoutMs))
    {
        // 超时后即使没完成,也要调用EndInvoke避免资源泄漏
        cadControl.EndInvoke(asyncResult);
        throw new TimeoutException("获取CAD文件名超时");
    }

    return fileName;
}
解决方案2:先探测CAD状态再执行操作

比起超时后终止调用,更高效的方式是提前判断CAD是否处于忙碌状态,避免触发阻塞调用。

方法A:利用CAD SDK自带的状态接口

很多CAD软件会提供判断自身是否空闲的API,比如:

  • AutoCAD:Application.IsQuiescent 属性,返回true表示CAD处于空闲状态
  • SolidWorks:ISldWorks.GetUserState() 可以判断是否在执行耗时操作

调用这些接口先做检查,只有当CAD空闲时才去获取文件名。

方法B:通过Windows API判断窗口响应状态

如果CAD没有提供状态接口,可以用Windows API发送测试消息,判断窗口是否响应:

[DllImport("user32.dll", SetLastError = true)]
private static extern bool SendMessageTimeout(
    IntPtr hWnd, 
    uint Msg, 
    IntPtr wParam, 
    IntPtr lParam, 
    uint fuFlags, 
    uint uTimeout, 
    out IntPtr lpdwResult);

private const uint SMTO_ABORTIFHUNG = 0x0002;
private const uint WM_NULL = 0x0000;

// 检查CAD窗口是否响应
public bool IsCadWindowResponsive(IntPtr cadWindowHandle)
{
    IntPtr result;
    // 发送WM_NULL消息,超时100毫秒,若窗口挂起会直接返回false
    return SendMessageTimeout(cadWindowHandle, WM_NULL, IntPtr.Zero, IntPtr.Zero, SMTO_ABORTIFHUNG, 100, out result);
}

使用时先调用IsCadWindowResponsive,返回true再执行文件名获取操作。

关键注意事项
  • 线程安全优先:务必查阅CAD SDK的官方文档,确认API是否允许跨线程调用。如果强制要求主线程,一定要用Invoke方式,否则会导致CAD崩溃或异常。
  • 超时后的资源清理:有些CAD操作一旦开始就无法中途取消,超时后可能需要后续处理残留的对象,避免内存泄漏。
  • 异常处理全覆盖:除了超时异常,还要捕获CAD API可能抛出的文档未打开、权限不足等异常,保证应用稳定性。

内容的提问来源于stack exchange,提问作者melkhaldi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:16:57