博图WinCC V16通过ADODB+DataGrid实现SQL Server数据查询与显示

发布时间:2026/10/12 6:49:33
博图WinCC V16通过ADODB+DataGrid实现SQL Server数据查询与显示
简介一份聚焦西门子博图WinCC V16与SQL Server数据库联动显示的实操笔记面向需要使用HMI实时呈现原材料等生产数据的自动化工程师与上位机开发人员。内容围绕ADODB组件与DataGrid控件展开先介绍数据库访问接口原理与控件特性再以“原材料信息”画面为例给出完整的VB脚本从创建Connection对象、配置Provider与数据源、打开连接到创建Recordset执行SQL查询、将DataGrid的DataSource绑定记录集并刷新显示。作者还整理了验证过程中遇到的典型问题与注意事项如游标位置选择、连接字符串设置、查询后对象释放等同时提及参数化查询与分页加载的优化方向。资源仅含1个docx文档压缩包大小约32KB轻便易用。已有3693人学习相关代码可直接迁移至WinCC V16项目适合希望快速打通数据库到画面数据链路的工程师参考。1. 博图WinCC V16连SQL Server为什么要用ADODBDataGrid先想清楚这是一条什么样的技术路线很多工控现场做到“设备数据上云”这一步才发现真正难的不是PLC把数据写进SQL Server而是把SQL Server里的数据摆到HMI画面上。博图WinCC V16在TIA Portal 16里提供了丰富的HMI画面对象但表格这块始终偏弱自带的表格控件读写外部数据库的能力很有限。ADODB是Windows上访问数据库最成熟的一套COM接口DataGrid则是微软的ActiveX表格控件两者配合可以稳定地在WinCC运行系统中显示SQL Server的查询结果。这套方案适合已经熟悉博图和WinCC组态、需要做“数据库查询页”或“报表展示页”的自动化工程师不需要额外买报表软件也不需要改动PLC程序一次搭好就能长期用。2. 搭好两头基础SQL Server库表与WinCC V16的ActiveX控件环境在写任何脚本之前先把数据库侧和WinCC侧的条件准备齐全否则后面调试时你会分不清是连接串写错了、还是控件没注册成功最后只能瞎试。这章分成三块SQL Server的认证和表结构、WinCC V16画面里DataGrid控件的放置方式、以及一个提前验证连通性的最小步骤。2.1 SQL Server侧的三个准备认证模式、目标库、最小权限账号数据库版本方面SQL Server 2008 R2、2012、2016、2019都可以包括Express版。一般做一个HMI查询页数据量不会太大Express版足够但要注意Express默认安装时的网络配置。安装时一定要选混合模式认证而不是Windows身份验证模式因为WinCC脚本运行时使用的Windows账户不一定是当前操作账户直接走Windows身份验证容易因为账户权限不可控而失败。建库和建表用一段SQL就能完成下面这段在我常用的SQL Server 2019上直接执行即可CREATE DATABASE WinCCData; GO USE WinCCData; GO CREATE TABLE dbo.ProductionRecord ( ID INT IDENTITY(1,1) PRIMARY KEY, ProductCode NVARCHAR(50), Quantity INT, PassCount INT, FailCount INT, RecordTime DATETIME DEFAULT GETDATE() ); GO -- 为WinCC创建一个专用登录账号避免在画面脚本里写死sa密码 IF NOT EXISTS (SELECT 1 FROM sys.sql_logins WHERE name Nwincc_user) BEGIN CREATE LOGIN wincc_user WITH PASSWORD NWincc123456, CHECK_POLICY ON, CHECK_EXPIRATION ON; END GO USE WinCCData; GO CREATE USER wincc_user FOR LOGIN wincc_user; GO GRANT SELECT ON dbo.ProductionRecord TO wincc_user; GO这一段SQL里有三个参数值得注意。第一CHECK_POLICY ON要求密码符合系统策略如果SQL Server所在机器有密码过期策略登录可能在某一天突然失效这就是很多运行一两年的项目突然连不上的原因后面避坑章节会细说。第二登录名和数据库用户名不能混为一谈上面先建 login 再建 user很多初学者只建了 login 就以为完成了。第三权限只给了SELECT如果后面要做写入可以再补INSERT、UPDATE权限先把最小权限立起来避免HMI页面被注入或误操作破坏数据。2.2 在WinCC V16画面里添加DataGrid控件的两个入口打开博图V16项目进入HMI画面编辑界面在右侧工具箱里找到“控件”分类里面一般会有ActiveX控件列表DataGrid显示为“DataGrid Control”或“Microsoft DataGrid Control 6.0”。把它拖拽到画面里调整好位置和大小。如果在“控件”分类里找不到可以在工具箱空白处右键选择“选择ActiveX控件”在弹出的系统清单里勾选 MSDATGRD.OCX 对应的项确认后它就会出现在工具箱里。这里有一个容易忽略的细节DataGrid控件在开发机器上可见可拖不代表部署到运行机器后也能正常工作。MS DataGrid控件需要运行许可授权这在博图WinCC V16运行系统启动时会检查。常见做法是在部署机器上安装一次微软数据访问组件或者将开发机上注册表中的License项导出导入到目标机器。这个坑我在第五章专门展开。插入控件后记住它画面中的对象名默认叫DataGrid1。后面VBS脚本里访问它靠的就是这个名字我一般不会改成容易拼错的名字因为脚本里出现一次拼写错误运行时就只会报“对象未找到”查起来反而费时间。2.3 连通性预检在SSMS先用一条查询确认数据和访问权限WinCC脚本本身不用数据库工具但调试时手里必须有一个能直接执行SQL的工具。SQL Server Management Studio是基础也有工程师用Navicat for SQL Server替代。操作顺序是先在SSMS里用wincc_user登录数据库实例执行USE WinCCData切换库最后运行一条查询比如SELECT TOP 100 * FROM dbo.ProductionRecord ORDER BY RecordTime DESC。如果这一步失败就不要急着写WinCC脚本先在数据库工具里把连接问题解决掉。常见的失败原因是“TCP/IP连接超时”或“登录失败”前者多数是SQL Server配置管理器里TCP/IP协议处于禁用状态后者是登录名或密码错误、或者账号在数据库中无权选表。这一步做得越早后面调试成本越低。我第一次做这个方案时没做预检在连接串、防火墙、端口之间来回折腾了几个小时最后发现是SQL Server服务没重启导致TCP/IP配置未生效。SSMS既然能连上说明服务端和客户端路径基本没问题剩下的就是WinCC侧脚本的写法。3. ADODB连接串与VBS脚本从按钮事件跑通第一条查询接下来是重点。博图WinCC V16画面里执行脚本的环境是VBScriptADODB对象模型在VBScript里全部可用。你要做的就是在按钮的“单击”事件里依次完成创建Connection、创建Recordset、执行SQL、绑定DataGrid、关闭释放。每一步都有顺序要求也有参数选择上的讲究。3.1 连接字符串的关键参数Provider、Data Source、Initial Catalog和认证连接字符串是ADODB里最直观也最容易写错的部分。一个典型连接串如下ProviderSQLOLEDB;Data Source192.168.1.10;Initial CatalogWinCCData;User IDwincc_user;PasswordWincc123456逐个拆解来看。ProviderSQLOLEDB表示使用微软的OLE DB Provider for SQL Server这是Windows系统自带驱动兼容性最好较少依赖额外安装。如果目标机器上装了SQL Server 2012以上的客户端组件也可以换成ProviderSQLNCLI11或SQLNCLI10效果一样。Data Source就是目标SQL Server实例的IP或机器名默认实例写IP即可命名实例要写成IP\实例名格式。Initial Catalog是要访问的数据库名对应上面建的WinCCData。User ID和Password是数据库登录凭据。这里有一个工程上的惯例不要把sa账号放在画面脚本里。一是权限过大万一画面脚本被改成非法操作伤害面太大二是sa密码也会因为系统策略到期。用最小权限账号加固定密码能省去很多维护上的麻烦。3.2 用VBS脚本在画面按钮上执行查询并绑定DataGrid在画面里放一个“查询”按钮双击进入事件编辑选择“单击”事件写入下面这段VBS脚本Sub OnClick(ByVal Item) Dim objConn, objRS, strSQL 第1步创建连接对象并打开 Set objConn CreateObject(ADODB.Connection) objConn.ConnectionString ProviderSQLOLEDB;Data Source192.168.1.10;Initial CatalogWinCCData;User IDwincc_user;PasswordWincc123456 objConn.Open 第2步创建记录集执行查询 Set objRS CreateObject(ADODB.Recordset) objRS.CursorLocation 3 adUseClient客户端游标 strSQL SELECT ID, ProductCode, Quantity, PassCount, FailCount, RecordTime FROM ProductionRecord ORDER BY RecordTime DESC objRS.Open strSQL, objConn, 3, 1 adOpenStatic3, adLockReadOnly1 第3步绑定到DataGrid显示 With ScreenItems(DataGrid1) On Error Resume Next Set .Recordset objRS If Err.Number 0 Then 博图WinCC里ActiveX控件封了一层部分属性要加 .Object 访问 Set .Object.Recordset objRS End If On Error GoTo 0 End With 第4步关闭记录集和连接 objRS.Close objConn.Close Set objRS Nothing Set objConn Nothing End Sub代码逻辑顺序是固定的创建、打开、查询、绑定、关闭。其中绑定这块在博图WinCC里有一个“双保险”的写法先尝试直接给ScreenItems(DataGrid1).Recordset赋值如果代理属性不暴露底层COM接口再用.Object.Recordset访问。我在部分WinCC V16补丁版本里遇到过直接访问Recordset会提示“对象不支持该属性或方法”改成.Object.Recordset就好了。参数方面objRS.Open的第三、四两个参数分别代表游标类型和锁定类型。3是静态游标对应adOpenStatic1是只读锁定对应adLockReadOnly。只做显示用途时这两个值是最稳的组合。如果后面你需要在画面里修改记录集再回写数据库才需要考虑其他锁定类型。注意如果你用的博图WinCC V16是早期Update版本绑定数据后可能遇到“类未注册”提示先查系统和WinCC的Update补丁版本。.Object.Recordset和直接.Recordset两种写法选你环境里实测通过的那一种固定下来。3.3 游标位置和锁定类型为什么DataGrid显示空白要检查这两项DataGrid控件对记录集有两个隐性要求。第一游标位置必须是客户端adUseClient也就是CursorLocation 3。服务端游标下DataGrid可能只能拿到一行或者完全空白因为记录集绑定时需要本地缓冲。第二游标类型必须是静态游标3这样DataGrid才能把整个结果集在本地构建出表格结构。如果你发现按了按钮后DataGrid不报错、但表格一片空白优先检查这两行。另外如果你的查询里有WHERE条件建议把条件写在SQL里而不是在记录集生成后再用ADO的Filter属性过滤。Filter属性虽然可以本地过滤但过滤大结果集时的表现远不如SQL Server的索引查得快HMI运行内存也扛不住全表数据。3.4 释放连接的三条规则Close、Set Nothing和避免重复连接释放是新手最容易忽略的环节。第一条规则是关闭顺序先关闭记录集再关闭连接。反过来操作记录集还持有连接引用连接可能不会真正释放。第二条规则是对象必须Set Nothing。VBScript没有自动垃圾回收机制光Close不Nothing对象资源不会立即释放长时间运行在WinCC里堆对象就要出问题。第三条规则是不要在全局脚本里长期持有一个打开的Connection。频繁开关连接看起来是浪费但对WinCC运行时来说短连接比长连接可靠它不会被数据库会话中断、锁定冲突这类问题拖垮。我自己的习惯是所有数据库操作都在同一个Sub内完成打开和关闭绝不让连接对象跨函数传递。4. 让DataGrid按需刷新定时器脚本、查询条件和显示列控制跑通一次查询只是第一步生产场景里通常需要做到“操作工输条件、点查询、看到结果、定期刷新”。这章把运行体验层面的东西补上列头中文显示、输入参数拼接时的转义、以及定时自动刷新时不踩“画面未打开”的坑。4.1 DataGrid在运行时的外观控制列标题、行高和中文显示DataGrid的列标题默认取自SQL查询结果的字段名英文名直接显示不利于操作工阅读。两个办法一是SQL里用别名把英文列名改成中文标题二是运行时通过脚本设置列对象的Caption属性。SQL别名方式最简单SELECT ID AS 序号, ProductCode AS 产品编码, Quantity AS 数量, PassCount AS 合格数, FailCount AS 不良数, RecordTime AS 记录时间 FROM ProductionRecord这种方法的局限是DataGrid自动生成的列顺序和标题完全由SQL决定如果你要在脚本里动态改列宽、列标题就得等记录集绑定后遍历ScreenItems(DataGrid1).Object.Columns集合来设置Dim colIdx For colIdx 0 To ScreenItems(DataGrid1).Object.Columns.Count - 1 ScreenItems(DataGrid1).Object.Columns(colIdx).Width 60 Next这里.Object是博图WinCC访问ActiveX真实接口的标准写法前面直接用.Recordset其实是碰运气能走通是因为部分代理属性被放行。列宽按内容自动调整在运行时是个黑匣子不同分辨率下显示效果不一样建议固定列宽而不要用自动宽度否则几行内容长短不一时表格会被撑得很难看。4.2 按条件查询把输入域的值拼进SQL语句时注意转义给画面加上查询条件输入域然后拼接SQL新手常见错误是直接把输入框文本塞进SQL字符串。比如输入框里输入一个单引号SQL语句就断掉了轻则报错重则被拼出危险的执行语句。虽然HMI操作场景多数是工厂内网但防御性写法成本很低不用白不用Dim strInput, strWhere, strSQL strInput ScreenItems(IOField_ProductCode).OutputValue strInput Replace(strInput, , ) 单引号翻倍避免SQL断句 strInput Trim(strInput) If strInput Then strWhere WHERE ProductCode LIKE % strInput % Else strWhere End If strSQL SELECT ID AS 序号, ProductCode AS 产品编码, Quantity AS 数量, RecordTime AS 时间 FROM ProductionRecord strWhere ORDER BY RecordTime DESC参数说明Replace(strInput, , )是应对单引号注入的常用手段。SQL Server里两个连续单引号表示一个单引号字面量这样不管输入什么内容拼出来的SQL都不会破坏原有语句。OutputValue返回输入域的对象值如果用户没有输入内容返回空字符串所以要加一个Trim判断避免生成WHERE ProductCode LIKE %%这种没意义的全文匹配查询。4.3 定时刷新全局脚本按周期重查但先判断画面是否打开生产看板类页面希望每隔几秒自动刷新。做法是在WinCC的全局脚本里建立一个周期触发的脚本脚本内容和按钮点击事件几乎一样只是多两步检查画面是否处于活动状态、绑定目标是否还存在。Sub RefreshData() Dim objConn, objRS, strSQL, tmpCtrl, bScreenOpen bScreenOpen False 画面不在当前显示页时跳过刷新避免脚本报错 On Error Resume Next Set tmpCtrl ScreenItems(DataGrid1) If Err.Number 0 Then bScreenOpen True End If On Error GoTo 0 If Not bScreenOpen Then Exit Sub End If Set objConn CreateObject(ADODB.Connection) objConn.ConnectionString ProviderSQLOLEDB;Data Source192.168.1.10;Initial CatalogWinCCData;User IDwincc_user;PasswordWincc123456 objConn.Open Set objRS CreateObject(ADODB.Recordset) objRS.CursorLocation 3 strSQL SELECT TOP 200 ID AS 序号, ProductCode AS 产品编码, Quantity AS 数量, RecordTime AS 时间 FROM ProductionRecord ORDER BY RecordTime DESC objRS.Open strSQL, objConn, 3, 1 ScreenItems(DataGrid1).Object.Recordset objRS objRS.Close objConn.Close Set objRS Nothing Set objConn Nothing End Sub这个脚本里有两个细节值得说。一是用On Error Resume Next探测ScreenItems(DataGrid1)是否可访问这是对博图WinCC全局脚本里“画面可能未加载”场景的容错处理。直接访问不存在的画面对象会抛错并中断脚本加了容错后可以优雅跳过。二是查询里加了TOP 200限制返回行数看板显示不需要全表数据限制行数能显著降低DataGrid刷新的卡顿感也能避免一次查询拉回几万行把HMI运行内存拖垮。5. 避坑连接超时、空白表、按钮无反应与许可证问题的排查记录这一章写我从实际项目里踩过、也给客户排过的坑。每一条都按“现象、原因、解决”来写按这个顺序排查能省掉多数现场调试的冤枉路。5.1 SQL Server连接超时先查TCP/IP协议和1433端口再查防火墙现象是WinCC运行时单击查询按钮后脚本卡住几秒然后报“连接超时”或“未指定错误”但SSMS在开发机上连接又正常。原因通常是两个SQL Server的TCP/IP协议未启用或者Windows防火墙拦截了1433端口。很多Express版在安装时默认不启用TCP/IPSSMS通过共享内存或命名管道能连上但OLEDB走TCP/IP就连不上。解决步骤是在SQL Server配置管理器中确认“SQL Server网络配置”下的TCP/IP协议状态为“已启用”右键属性里确认“IP地址”部分将目标IP或“IPAll”的TCP端口设置为1433然后重启SQL Server服务最后在防火墙入站规则里放行1433端口。改完后用SSMS以TCP/IP方式重连一次确认服务器名称写的是IP而不是机器名。5.2 认证失败的坑密码过期、登录名和用户名混乱、以及策略锁定现象是连接串没问题但登录报“用户登录失败”在SSMS里用同一个账号却能登录。这听起来矛盾多数原因其实是密码过期策略。我遇到过现场一台SQL Server 2012的实例启用了密码策略wincc_user的密码过期后WinCC脚本报错SSMS登录时提示用户必须修改密码。解决方法是临时禁用该登录的密码过期策略ALTER LOGIN wincc_user WITH CHECK_EXPIRATION OFF, CHECK_POLICY OFF;这里把CHECK_POLICY也关了因为现场环境如果没有域策略强制复杂密码就让它保持简单固定密码省得下一次又因为策略锁定。还有一个容易混淆的地方SQL Server的login是实例级的database user是数据库级的。如果只创建了login没有在WinCCData库里创建对应的user并授予SELECT权限就会出现“对对象ProductionRecord的SELECT权限被拒绝”这类报错。5.3 DataGrid显示空白但脚本不报错缺少客户端游标现象是按钮执行完DataGrid区域完全是空的也没报错弹窗。这种“安静失败”最让人头疼。原因就是第3章提到的CursorLocation没有被设置为客户端游标。默认情况下记录集使用服务端游标DataGrid在绑定服务端游标结果时不会主动报错只是拿不到完整结果集。解决就是补上两行objRS.CursorLocation 3和游标类型3。如果已经补上还是空白再检查查询是否返回了零行记录这个用SSMS跑一遍相同SQL就能确认。5.4 博图V16运行和仿真器按钮无反应脚本没触发的逻辑排查现象是点击画面里的查询按钮没有任何反应如果把同样的脚本放到另一台运行环境中又能执行。很多工程师会怀疑是ADODB的问题其实按钮无反应往往跟数据库毫无关系。在博图WinCC里按钮事件脚本没触发有几个常见根因。第一是按钮的“启用”属性为否或画面处于“运行系统仿真”模式而项目里脚本还没编译进去网上常说的“博图HMI仿真按钮无反应”多数是这类。第二是画面事件没有被正确挂载比如双击按钮后在事件列表里选错了事件节点把脚本写到了“释放”而不是“单击”。第三是全局脚本里出现了导致运行时终止的异常第一个报错后的脚本被HMI运行时挂起之后所有按钮都无响应。排查顺序建议是先用一条最简单的测试脚本比如ScreenItems(IA_Test).Text OK确认按钮事件通道是通的然后再叠加ADODB逻辑。如果测试脚本也没反应问题基本在按钮属性或运行系统配置不需要碰数据库。5.5 MS DataGrid控件在目标机器上报“许可证未找到”现象是开发机上运行正常把博图WinCC V16项目部署到另一台Windows机器上运行后画面加载DataGrid时提示类似“没有许可证”或控件初始化失败。原因是MS DataGridMSDATGRD.OCX属于需要运行时许可证的ActiveX控件许可证密钥存在注册表的HKEY_CLASSES_ROOT\Licenses下目标机器没装过Visual Basic或相关开发组件时就会缺这个键。解决方案有两类一类是找到开发机上的HKEY_CLASSES_ROOT\Licenses整个项导出再导入目标机器另一类是把MSDATGRD.OCX用regsvr32重新注册再手动创建对应的许可证注册表项。第二种操作比较繁琐现场我一般优先用导出导入方式最快而且不会影响其他COM组件。6. 进阶思路参数化查询、限行显示和一次写库的优化方向业务运行几个月后你多半会碰到两个新需求一是查询页上的条件越来越多二是要把操作记录回写到另一张表。这里说两个值得尽早落地的做法。关于参数化查询前面说的Replace防单引号是应急手段但更稳的做法是使用ADO的Command对象加参数。VBScript里用CreateObject(ADODB.Command)创建命令对象通过cmd.Parameters.Append传入查询参数SQL文本和值分离从机制上避免了拼接注入。接上文已经打开的objConn示例代码如下Dim objCmd Set objCmd CreateObject(ADODB.Command) Set objCmd.ActiveConnection objConn objCmd.CommandText SELECT * FROM ProductionRecord WHERE ProductCode ? objCmd.Parameters.Append objCmd.CreateParameter(code, 200, 1, 50, strInput) Set objRS objCmd.Execute参数说明200是adVarChar1是adParamInput50对应字段长度strInput是画面输入域的值。用Command对象后不再手工拼SQL查询语句的维护也变得更清晰。关于结果集限行和DataGrid性能我的习惯是所有看板类查询都加TOP 200或TOP 500同时用ORDER BY RecordTime DESC把最新记录排在最前。如果确实需要查看更早的历史数据再提供“下一页”按钮用OFFSET FETCH分页查询而不是一次把全表拉到内存。关于写库ADODB一样可以执行INSERT和UPDATE。比Recordset.Open更适合的方式是直接objConn.Execute执行一条带参数的INSERT语句。注意写入时也要用参数化方式并确保连接串里使用的账号有INSERT权限。这样你的HMI不只是一个查询终端也能承担简单的数据录入和状态回写功能。最后提醒一句我的个人习惯连接串不要散落在每个画面脚本里写死明文尤其是包含生产环境密码时尽量在WinCC里建内部变量存放连接串脚本启动时从变量读取。这样做的好处是密码集中管理数据库账号要轮换时只改一处不用翻开整个项目找脚本。这套ADODB加DataGrid的方案我在两条产线的追溯看板上已经跑了两三年稳定性关键就在于连接串受控、结果集限行、释放彻底这三条。希望帮到你。本文还有配套的精品资源点击获取