【自动化】C# UIAutomationClient实战:从零构建高效桌面自动化脚本

C#桌面自动化实战:用UIAutomationClient操控Windows计算器(附完整代码) 本文详细介绍了如何使用C#和UIAutomationClient实现Windows计算器的桌面自动化控制,包括环境配置、核心API解析、实战代码示例及高级技巧。通过完整的代码演示和异常处理方案,帮助开发者快速掌握桌面自动化技术,提升工作效率。 阅读详情

1. 从零认识你的桌面“遥控器”:UIAutomationClient

大家好,我是老张,一个在自动化领域摸爬滚打了十来年的老码农。今天想和大家聊聊一个我用了很多年,但感觉很多C#开发者还没完全用起来的“神器”——UIAutomationClient。简单来说,它就是Windows系统给你的一把“万能遥控器”,让你能用代码去操控电脑上几乎所有的桌面程序,比如自动填写表单、点击按钮、读取窗口信息,甚至操作那些没有标准窗口句柄的现代WPF控件。听起来是不是有点像外挂或者脚本?但它其实是微软官方提供的、正儿八经的自动化框架,核心目的就是为了辅助功能(比如屏幕阅读器)和自动化测试。

我刚开始接触它的时候,也觉得概念有点多,API看起来不那么直观。但真正用上手之后,发现它在处理一些重复性的桌面办公任务,或者给老旧但核心的Win32程序写自动化测试脚本时,简直是“救命稻草”。它不像一些基于图像识别的自动化工具那样“傻”,它直接和程序的UI底层结构对话,定位精准,执行稳定。举个例子,我们之前有个项目需要每天从某个古老的财务软件里导出数据,手动操作要花半小时,还容易出错。我用UIAutomationClient写了个不到两百行的小脚本,每天上班前自动跑一下,喝杯咖啡的功夫数据就整理好了,省下的时间不知道能摸多少鱼(划掉)……能研究多少新技术。

那么,谁适合学这个呢?如果你是一名测试工程师,厌倦了重复的手工点击;如果你是一名开发者,想为自己写的桌面应用添加自动化测试套件;或者你只是一个想用技术解放双手、自动化处理日常电脑操作的效率爱好者,那么UIAutomationClient都值得你投入时间。它不需要你懂复杂的图形学或者钩子技术,只要你熟悉C#,就能快速上手。接下来,我就带你一步步拆解这个“遥控器”的使用说明书,从安装电池(引用库)开始,到编写第一个能自动操作计算器的脚本。

2. 开工前的必备工具:Inspect,你的UI“显微镜”

在开始写代码之前,我必须先给你安利一个至关重要的工具——Inspect。你可以把它想象成给应用程序界面做“X光透视”的显微镜,或者是一把“瑞士军刀”。没有它,搞UIAutomation就像蒙着眼睛在迷宫里找路,全靠猜;有了它,你就能清晰地看到每个按钮、文本框的“内在属性”,从而知道用什么“咒语”(代码)去控制它。

这个工具是微软官方出品的,通常随着Windows SDK一起安装。如果你没有,可以去微软官网下载Windows SDK,或者直接在Visual Studio Installer里勾选“Windows 10 SDK”之类的选项。安装好后,你可以在开始菜单搜索“Inspect”,或者到SDK的安装目录(比如 C:\Program Files (x86)\Windows Kits\10\bin\10.0.xxxxx.0\x64)下找到 Inspect.exe。

打开Inspect,它的界面可能有点复古,但功能强大。最常用的模式是鼠标移动到屏幕任意位置,它就会实时高亮显示当前鼠标所指的UI元素,并在右侧面板中列出该元素的所有UIA属性。这些属性就是我们写代码定位元素的依据。我习惯在开发时,把Inspect窗口和Visual Studio并排放在一起。比如,我想自动化操作记事本,我会先打开记事本,然后用Inspect的鼠标指针去点一下记事本的编辑区域。这时,Inspect会显示这个编辑框的 ControlType 是 Document 或 Edit,Name 可能是空,但 AutomationId 或者 ClassName 会有像 Edit 这样的值。

这里有个我踩过的坑要提醒你:优先使用 AutomationId 来定位元素。这个属性相当于UI元素的身份证号,通常是开发者在代码里设置的,理论上应该是唯一且稳定的。比如Visual Studio里一个“保存”按钮,它的 Name 可能是“保存(S)”,这个文本可能随语言版本变化,但它的 AutomationId 可能是 "FileSave" 这样的内部标识,稳定得多。如果 AutomationId 没有(很多传统Win32程序确实没有),那就退而求其次,结合 Name(显示文本)和 ControlType(控件类型,如Button)来定位。Inspect能让你一眼就看到这些信息,帮你制定出最可靠的定位策略。

3. 搭建你的C#自动化工程:引入核心库

工欲善其事,必先利其器。用C#来玩转UIAutomation,第一步就是在你的项目里把“武器库”引进来。这个过程非常简单,几乎就是点几下鼠标的事。

如果你用的是Visual Studio(我猜大部分C#开发者都是),那么:

  1. 在“解决方案资源管理器”里,右键点击你的项目。
  2. 选择“添加” -> “引用…”。
  3. 在弹出的窗口中,切换到“程序集”或者“浏览”选项卡旁边的“框架”列表(取决于你的项目类型,.NET Framework项目通常在“程序集”里找,.NET Core/.NET 5+可能需要通过NuGet)。
  4. 在列表里找到并勾选 UIAutomationClient 和 UIAutomationTypes。这两个是核心,必须引用。
    • UIAutomationClient:包含了所有用来查找和操作UI元素的主要类,比如 AutomationElement。
    • UIAutomationTypes:定义了很多枚举和模式接口,比如 ControlType.Button, InvokePattern 等。
  5. 点击“确定”,引用就添加好了。

对于现代的.NET Core/ .NET 5+ 项目,你可能需要通过NuGet包管理器来添加。在NuGet中搜索 System.Windows.Automation,这个包通常就包含了上述两个程序集。在包管理器控制台中输入 Install-Package System.Windows.Automation 即可。

引用添加成功后,在你的C#代码文件顶部,记得加上命名空间引用:

using System.Windows.Automation;

这样,你就可以在代码里畅快地使用 AutomationElement、Condition 这些关键类了。我个人的习惯是会创建一个单独的类库项目来封装所有自动化操作,这样业务逻辑和自动化控制能分离得更清晰,也方便复用。

4. 核心操作一:如何精准“找到”目标控件

好了,工具和库都准备好了,现在我们进入实战最核心的部分——定位元素。你可以把这想象成在茫茫人海中找一个特定的人。UIAutomation提供了几种“寻人启事”的写法。

首先,你得知道从哪儿开始找。 一切的起点通常是 AutomationElement.RootElement,它代表整个桌面。但更常见的场景是,你先找到目标应用程序的主窗口。有两种经典方法:

  1. 通过进程找窗口:如果你知道目标程序的进程,可以先用 Process 类启动或获取它,然后拿到主窗口句柄,再用 AutomationElement.FromHandle 转换。
    Process notepadProc = Process.Start("notepad.exe");
    // 稍微等一下,等窗口创建出来
    Thread.Sleep(1000);
    AutomationElement notepadWindow = AutomationElement.FromHandle(notepadProc.MainWindowHandle);
    
  2. 通过窗口属性直接找:如果你知道窗口的标题,可以直接从桌面根元素下查找。
    Condition windowCondition = new PropertyCondition(AutomationElement.NameProperty, "无标题 - 记事本");
    AutomationElement notepadWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, windowCondition);
    

找到主窗口后,就要在窗口里找具体的按钮、文本框了。 这里最常用的就是 FindFirst 或 FindAll 方法,配合 Condition(条件)来筛选。TreeScope 参数决定搜索范围,Children 只找直接子元素,Descendants 会递归查找所有后代元素,功能更强大但也更耗性能。

最强大、最常用的条件是 PropertyCondition,即根据属性来定位。我强烈建议你按照这个优先级来组合条件:

  1. 黄金组合:AutomationId。如果控件有,且唯一,就用它。new PropertyCondition(AutomationElement.AutomationIdProperty, "txtUserName")
  2. 白银组合:Name + ControlType。用 AndCondition 把两者组合起来,能极大提高准确性。比如找一个名叫“登录”的按钮:
    Condition nameCond = new PropertyCondition(AutomationElement.NameProperty, "登录");
    Condition typeCond = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button);
    Condition finalCond = new AndCondition(nameCond, typeCond);
    AutomationElement loginButton = window.FindFirst(TreeScope.Descendants, finalCond);
    
  3. 青铜选择:ClassName。有些传统控件,类名比较有特征,比如Windows计算器里的按钮类名就是“Button”。

有时候界面元素是动态加载的,你直接找可能找不到。这时就需要一个等待机制。我写了一个 helper 方法,在很多项目里都用得上:

public static AutomationElement WaitForElement(AutomationElement root, Condition condition, int timeoutMs = 10000)
{
    DateTime endTime = DateTime.Now.AddMilliseconds(timeoutMs);
    while (DateTime.Now < endTime)
    {
        AutomationElement element = root.FindFirst(TreeScope.Descendants, condition);
        if (element != null)
            return element;
        // 不要用 Thread.Sleep,这里只是示例,实际建议用 Task.Delay
        System.Threading.Thread.Sleep(200);
    }
    throw new TimeoutException($"在 {timeoutMs} 毫秒内未找到元素。");
}

5. 核心操作二:与控件交互的“模式”大法

找到控件(AutomationElement)只是第一步,就像你找到了电视遥控器,但还得知道按哪个键是换台,哪个键是调音量。在UIAutomation里,这个“键”的概念就是 Pattern(模式)。不同的控件支持不同的模式,你需要获取对应的模式对象,然后调用其方法。

如何知道控件支持什么模式? 还是得靠我们的老朋友Inspect。在Inspect里选中一个元素,看它的“支持的模式”列表。常见的模式有:

  • InvokePattern:用于触发操作,比如点击按钮、菜单项。调用 Invoke() 方法。
  • ValuePattern:用于有“值”的控件,比如文本框、滑块。可以 GetValue() 读取,SetValue(string) 写入。
  • SelectionItemPattern:用于列表项、单选按钮等可被选中的项。调用 Select()。
  • ExpandCollapsePattern:用于可以展开/折叠的控件,如树形节点、下拉框。调用 Expand() 或 Collapse()。
  • TogglePattern:用于有两种状态的控件,如复选框。调用 Toggle() 来切换状态。

代码里怎么用呢? 这里有个标准三步曲,我以点击按钮和设置文本框为例:

// 假设 buttonElement 是之前找到的按钮 AutomationElement
// 1. 检查是否支持该模式(好习惯,避免异常)
object isInvokeAvailable = buttonElement.GetCurrentPropertyValue(AutomationElement.IsInvokePatternAvailableProperty);
if (isInvokeAvailable is bool b && b)
{
    // 2. 获取模式对象
    InvokePattern invokePattern = (InvokePattern)buttonElement.GetCurrentPattern(InvokePattern.Pattern);
    // 3. 调用模式方法
    invokePattern.Invoke();
}

// 假设 textBoxElement 是文本框
object isValueAvailable = textBoxElement.GetCurrentPropertyValue(AutomationElement.IsValuePatternAvailableProperty);
if (isValueAvailable is bool b2 && b2)
{
    ValuePattern valuePattern = (ValuePattern)textBoxElement.GetCurrentPattern(ValuePattern.Pattern);
    // 设置文本值
    valuePattern.SetValue("你好,世界!");
    // 读取文本值
    string currentText = valuePattern.Current.Value;
}

这里有个细节:获取模式对象时,最好使用 GetCurrentPattern 并转换类型,而不是直接访问 Current 属性下的模式(虽然有些模式也可以)。前者是更标准和安全的方式。

6. 实战演练:组装一个自动化计算器脚本

光说不练假把式,我们现在就把前面学的所有东西串起来,写一个能自动操作Windows计算器,并完成一次计算的完整脚本。这个例子非常经典,因为它涵盖了启动程序、查找窗口、定位按钮、触发点击、读取结果等全套流程。

using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;

class CalculatorAutomation
{
    static void Main()
    {
        try
        {
            Console.WriteLine("正在启动计算器...");
            // 启动计算器进程
            ProcessStartInfo startInfo = new ProcessStartInfo("calc.exe");
            Process calcProcess = Process.Start(startInfo);

            // 重要:给窗口一点时间启动和初始化
            Thread.Sleep(2000);

            // 方法1:通过进程句柄找窗口(更直接)
            AutomationElement calcWindow = AutomationElement.FromHandle(calcProcess.MainWindowHandle);

            // 方法2:如果方法1不行,尝试通过窗口标题找(备用)
            if (calcWindow == null)
            {
                Condition titleCondition = new PropertyCondition(AutomationElement.NameProperty, "计算器");
                calcWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, titleCondition);
            }

            if (calcWindow == null)
            {
                Console.WriteLine("错误:找不到计算器窗口。");
                return;
            }
            Console.WriteLine("成功找到计算器窗口。");

            // 定义一个通用的点击按钮方法
            void ClickButton(string buttonName)
            {
                // 组合条件:名字是按钮名,且控件类型是按钮
                Condition btnCondition = new AndCondition(
                    new PropertyCondition(AutomationElement.NameProperty, buttonName),
                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)
                );

                AutomationElement btn = calcWindow.FindFirst(TreeScope.Descendants, btnCondition);
                if (btn != null)
                {
                    // 获取并调用Invoke模式
                    InvokePattern invoke = (InvokePattern)btn.GetCurrentPattern(InvokePattern.Pattern);
                    invoke.Invoke();
                    Console.WriteLine($"已点击按钮:{buttonName}");
                    // 每次操作后稍作停顿,模拟人类操作速度,也让UI有反应时间
                    Thread.Sleep(150);
                }
                else
                {
                    Console.WriteLine($"警告:未找到按钮 '{buttonName}',请用Inspect工具确认按钮名称。");
                }
            }

            // 开始计算:5 + 3 =
            Console.WriteLine("开始执行计算:5 + 3 =");
            ClickButton("五");
            ClickButton("加");
            ClickButton("三");
            ClickButton("等于");

            // 获取计算结果
            // Windows 10/11 计算器的结果显示在一个 AutomationId 为 "CalculatorResults" 的元素里
            Condition resultCondition = new PropertyCondition(AutomationElement.AutomationIdProperty, "CalculatorResults");
            AutomationElement resultElement = calcWindow.FindFirst(TreeScope.Descendants, resultCondition);

            if (resultElement != null)
            {
                // 计算器的结果是通过元素的 Name 属性暴露的
                string resultText = resultElement.Current.Name;
                // 清理一下结果文本(可能包含“显示为”等前缀)
                Console.WriteLine($"计算完成!结果显示为:{resultText}");
            }
            else
            {
                Console.WriteLine("未找到结果显示区域。");
            }

            // 可选:点击“清除”按钮,或者直接关闭计算器
            // ClickButton("清除");
            Console.WriteLine("自动化操作完成。");
            // 不关闭进程,让计算器留着,你可以自己看看结果
            // calcProcess.Kill();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"程序运行出错:{ex.Message}");
            Console.WriteLine(ex.StackTrace);
        }
        finally
        {
            Console.WriteLine("按任意键退出...");
            Console.ReadKey();
        }
    }
}

把这段代码复制到一个控制台应用项目里,运行一下,你就能看到计算器被自动打开,并完成了5+3的计算。如果没成功,大概率是按钮的名称没对上。这就是为什么我一直强调先用Inspect看看:不同Windows版本(如Win7的计算器和Win10/11的计算器)按钮的 Name 属性可能不同,可能是中文“五”,也可能是“5”。根据Inspect看到的实际名称修改 ClickButton 的参数即可。

7. 避坑指南与性能优化:让脚本更健壮

脚本能跑起来只是第一步,要想在实际项目或长期任务中稳定运行,还得注意很多细节。这些都是我踩过坑、交过“学费”才总结出来的经验。

第一坑:元素状态瞬息万变。 你刚找到的元素,可能下一秒就被禁用、隐藏甚至销毁了。所以,异常处理必须到位。最常见的异常是 ElementNotAvailableException。在调用模式方法(如 Invoke)或读取属性时,用 try-catch 包起来是个好习惯。更优雅的做法是,在操作前检查元素的 IsEnabled、IsOffscreen 等状态属性。

第二坑:时机不对,一切白费。 自动化脚本跑得比人快,但UI反应需要时间。你点击一个按钮,可能半秒后才会弹出新窗口。如果代码立刻去查找新窗口里的元素,肯定找不到。所以,等待机制至关重要。前面提到的 WaitForElement 方法就是干这个的。避免使用固定的 Thread.Sleep,而是采用这种轮询检查的方式,效率更高。对于更复杂的事件,比如某个特定事件发生后才继续,可以使用 Automation.AddAutomationEventHandler 来订阅UI自动化事件。

第三坑:性能瓶颈。 FindFirst/FindAll 是相对耗时的操作,尤其是在遍历 Descendants 范围很大时。优化策略是:

  1. 缩小搜索范围:尽量从离目标近的父容器开始找,而不是每次都从根窗口开始。
  2. 缓存元素:对于频繁使用的元素(比如主窗口、导航栏),找到后存起来,别每次都重新查找。
  3. 使用更精确的条件:PropertyCondition 比 Condition.TrueCondition 快得多。多用 AndCondition 组合精确属性,减少返回的候选元素数量。

第四点:运行环境与权限。 有些应用程序(尤其是某些系统设置或需要管理员权限的软件)在普通用户权限下,UIAutomation可能无法正确识别或操作其控件。如果你的脚本在这种场景下失效,可以尝试以管理员身份运行你的自动化程序。在Visual Studio中调试时,也需要以管理员身份启动VS。

最后,关于线程。 UI自动化客户端API通常要求调用线程是STA(单线程单元) 线程。对于控制台应用程序,你需要在 Main 方法上标记 [STAThread] 特性。对于WPF或WinForms应用,主线程默认就是STA,一般没问题。

把这些注意事项记在心里,你的自动化脚本就能从“实验室玩具”升级为“生产级工具”。UIAutomationClient这套API确实需要一点学习成本,但一旦掌握,它给你带来的效率提升是巨大的。我从最初用它做简单的测试,到后来构建复杂的RPA流程,它始终是我在Windows桌面自动化领域的首选利器。希望这篇文章能帮你少走些弯路,更快地享受到自动化带来的乐趣和便利。如果在实践中遇到具体问题,多看看MSDN文档,多利用Inspect工具分析,问题总能解决的。

【自动化】UIAutomationClient高级技巧:C#桌面自动化性能优化与异常处理实战 本文深入探讨了C# UIAutomationClient在桌面自动化实战中的性能优化与异常处理高级技巧。针对常见的性能瓶颈,如滥用FindAll和频繁属性读取,文章提供了元素定位优化、智能等待机制及缓存策略等解决方案。同时,详细阐述了ElementNotAvailableException等关键异常的处理方法,帮助开发者构建稳定高效的自动化脚本。 阅读详情

相关推荐

Windows平台控件分析工具:Inspect软件

本文还有配套的精品资源,点击获取 简介:Inspect.rar 是一款适用于Windows系统的控件识别软件,以RAR格式压缩包形式提供。该工具便于用户检查和分析操作系统的用户界面元素,如窗口、按钮、文本框等,尤其在自动化测试和开发中十分有用。它能够提供控件属性信息、模拟用户交互,并帮助生成自动化脚本中的对象定位器,因此在编写使用Selenium或Appium的测试脚本时至...

weixin_42466723的博客 6671

Inspect(VB.NET、C#版)软件的的下载和使用

UIAutomation微软提sql教程供的UI自动化库,主要用AutomationElement类来表示UI 自动化目录树中的一个UI自动化元素,.NET Windows的窗java基础教程体应用程序和WPF应用程序。 Inspect是一款类似于SPY的界python基础教程面捕捉工具。外观如下: 下载地址:https://share.weiyun.com/5dpcNqx 进入该目c#教程录后,找到Inspect_VB.NET&C#.zip,下载到本地。 ..

chinaherolts2008的博客 1487

Inspect 自动化测试辅助工具

Inspect 自动化测试辅助工具Inspect 自动化测试辅助工具Inspect 自动化测试辅助工具

C#代码与面板(Inspector)的实用小技巧

话不多说直接进入正题 Tips1:[SerializeField] 可以把private修饰的字段序列化到Inspector面板上,看下图 Tips2:[Space] 直白意思空间,可以在c#脚本中用这个标签来调整字段在Inspector面板上的间隔,如下图 间隔是根据[Space]的个数来决定的,个数越多间隔越大 Tips3:[Header] 给在Inspector面板显示的字段加一个头部...

Marccco的博客 1005

inspect x64

微软控件识别工具X64,支持大部分控件,自动化测试的必备工具

Inspect.exe

自动化测试所需框架,学习自动化测试必备佳品工具,这个工具简单易上手

【自动化】深入浅出UIAutomationClient:C#桌面自动化实战指南

UI Automation (UIA) 是微软提供的一套强大的界面自动化技术,允许开发者与桌面应用程序的用户界面元素进行交互,无论这些控件是否有传统的窗口句柄。它广泛应用于自动化测试、辅助功能工具开发等领域。其中,UIAutomationClient是Microsoft提供的一套用于Windows桌面应用程序自动化的API,它是.NET Framework的一部分(位于。

Arbboter的专栏 3448

夏令营纪实——东南大学计科院&PALM实验室面试全解析

本文详细解析了东南大学计科院与PALM实验室夏令营的面试全流程,包括前期准备、技术考察、项目经验深挖等关键环节。特别针对自然语言处理(NLP)和机器学习(ML)领域的高频问题提供应对策略,帮助申请者提升面试表现。文章还分享了实用的准备技巧和面试经验,为有意向参加该夏令营的学生提供宝贵参考。

convnet3designer的博客 459

C#桌面自动化避坑指南:UIAutomationClient实战中常见的5个坑及解决方案

本文深入剖析了C#桌面自动化开发中,使用UIAutomationClient时常见的五大实战难题,包括元素定位失效、模式调用异常、性能瓶颈、权限问题及复杂UI处理。文章提供了经过验证的解决方案,如智能轮询等待、状态验证、资源管理与混合策略,旨在帮助开发者构建稳定高效的自动化测试或RPA工具,有效规避开发陷阱。

c2d3e4f的博客 420

机场数据治理系列介绍(1):机场行业数据中台中的数据管理顶层设计方案

民航机场行业的数据中台中,有关数据管理顶层设计方案需要结合机场行业的业务特点和技术需求进行具体的设计,今日我们简要考量设计提供一个参考方案:

机场信息系统研究员的专栏 1605

MyEclipse 2017 CI 10安装与激活

本文介绍MyEclipse 2017 CI 7、CI 8、CI 9和CI 10的安装与激活。此方法理论上应该能激活MyEclipse 2017 CI所有系列,即激活方法是通用的,只是激活文件略有不同。本文提供MyEclipse 2017 CI 7、CI 8、CI 9和CI 10的激活文件。说明:博主所提供的压缩包格式均为RAR5,即WinRAR 5.0以上的版本才能正常解压,别的压缩软件博主不太清...

weixin_42539046的博客 9417

UIAutomationClient避坑指南:解决元素定位失败的5个常见问题

本文深入探讨UIAutomationClient在桌面自动化中的5个高阶问题解决方案,包括动态ID处理、权限优化、性能提升、异步等待和复杂控件集成。通过C#代码示例和实战技巧,帮助开发者有效解决元素定位失败问题,提升自动化脚本的稳定性和效率。

h9j8k7l6m5n的博客 615

AI辅助需求分析与提示词生成

文章标题 《AI辅助需求分析与提示词生成》 关键词 人工智能 需求分析 提示词生成 深度学习 机器学习 强化学习 数学模型 系统架构

AI天才研究院 1215

AutoCut 实操教程:4 条命令用字幕批量剪辑 47 个视频

晚上 11 点,你的屏幕上还开着第 47 个录播 mp4——播放、拖进度条、记时间点、回剪辑软件删片段,这套动作今晚已经重复了 46 次。AutoCut 就是冲着这种机械劳动来的:它先把整段视频的音轨转成带时间戳的字幕文档,你像在改 Markdown 一样勾掉不想留的句子,剩下的片段自动剪成新片。说白了,它把"剪视频"降级成了"改一份字幕文档",重复劳动那部分全部交给脚本。 ## 2 分钟定义一

gitblog_00425的博客 432

C盘在同一时间突然多出100g的文件,请问是什么原因,以及是否能删除?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 1766

x2-DFD:A framework for explainable and explainable deepfake detection

该文章提出了X2-DFD框架,用于可解释和可扩展的深度伪造检测。通过评估大型多模态语言模型(MLLMs)在深度伪造检测中的内在能力,发现它们在不同伪造相关特征上的有效性各异。基于此,实施了针对性的微调策略,显著提高了MLLMs的解释能力,并整合了外部深度伪造检测器(EDDs),以结合MLLMs和传统检测器的互补优势,实现更好的检测和解释。

志在山顶的人,不会贪念山腰的风景 510

(转载)Unity C# Inspector小技巧

(转载)Unity C# Inspector小技巧 - 简书

weixin_45203752的博客 327

深入URP之Shader篇1: URP Shader概述

我们知道,URP和HDRP都是基于SRP的,尽管现在可以使用Shader Graph编写Shader,但是手写Shader仍然是有一定的优势,特别是在性能方面,手写Shader可以更极致的优化,因此我们在项目中前期都是直接使用Shader Graph编写Shader,项目后期会改成手写Shader来提高性能。而在SRP中手写Shader,我们仍然使用的是Shader Lab,这个结构并没有太大的变化,但是SRP Shader中使用Shader Lab语言还是有几点不同。

聚焦游戏和图形引擎开发技术 4639

inspect模块使用

inspect模块主要用于文件中类型判断等信息提取。

2051

ubuntu-emto-cpa 测试和使用(单核运行)

ubuntu-emto-cpa 测试和使用(单核运行)

qq_45834835的博客 1401

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Visual studio 2010 远程调试C#程序

日期:2015-6-12 环境: 主机:Win7SP1 64bits、Visual studio 2010SP1 被调试机:Windows2013 32bits、 参考资料实现了对C#的远程调试,符合下面二点很重要,折腾了很久。。。 [1]被调试机启动Visual Studio Remote Debugging Monitor程序的帐号(用户名和密码)必须同主机一致。 [2]Visua

lee353086的专栏 1232

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

奇妙的 Docker Inspect

奇妙的 Docker Inspect 模版 88250 • 1 年前 • 浏览 1.3K • 评论 0  Translation  Inspect  Template  模版  Docker  golang  概述 很多 Docker 用户都知道 docker inspect 命令,该命令用于获取容器/镜像的元数据,其中 -f 参数可以用于获取指定的数据,例

p656456564545的专栏 7591

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Python自省(反射)指南

在笔者,也就是我的概念里,自省和反射是一回事,当然其实我并不十分确定一定以及肯定,所以如果这确实是两个不同的概念的话,还请多多指教 :) 转载请注明作者、出处并附上原文链接,多谢!update 2011-3-10: 更正函数的func_globals属性含义。 首先通过一个例子来看一下本文中可能用到的对象和相关概念。 #coding: UTF-8 import sys # 模块...

weixin_30813225的博客 1210
上一篇: Qt中lambda表达式的实战技巧与陷阱解析
下一篇: MyBatis-Flex 逻辑删除与自动更新的实战技巧
python9snake
博客等级 码龄1天 0粉丝 1724原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值