• WinCC VBS利用EXCEL调用Windows API函数


    前面已经讨论过利用VBS的CreateObject方法来干很多以前不敢想象的事情,但Windows API却没有办法,虽有DynmicWrapper.dll这样的东西,毕竟使用起来不方便,而且功能也有限。如果利用EXCEL作为突破口,VBS调用EXCEL的宏,而由EXCEL的宏来调用Windows API正可以很好的解决这一问题。

    1. 简单举例 

    在API.XLS的Sheet1中加入如下代码:

    Private Declare Function SHShutDownDialog Lib "shell32" Alias "#60" (ByVal
    YourGuess
    As Long) As Long
    Public Sub ShowShutDownDlg() '显示关机界面
    SHShutDownDialog 0
    End Sub

    在WinCC调用之前先用EXCEL运行一下,效果如下:

    接下来由WinCC的VBS调用如下:

    Dim oExcelFile,oExcel,oWorkBook,oSheet
    oExcelFile
    = HMIRuntime.ActiveProject.Path + "\APIXLS\API.XLS"
    Set oExcel = CreateObject("Excel.Application")
    Set oWorkBook = oExcel.workbooks.OPen(oExcelFile)
    Set oSheet = oWorkBook.Sheets("Sheet1")
    oExcel.run
    "Sheet1.ShowShutDownDlg"
    oWorkBook.Close
    Set oWorkBook = Nothing
    oExcel.quit
    Set oExcel = nothing

    效果和EXCEL中是一模一样的,^_^。

    2. 如何传递参数,和取得返回值 

    但大多数时候我们需要调用一些API函数,传递某些值来获取返回值,比如FindWindow。

    oExcel.run传递参数是可以的,比如EXCEL有宏:

    Public Sub TestMsg(Msg As String)
    MsgBox Msg
    End Sub

    那么调用的时候用oExcel.run "Sheet1. TestMsg",”TEST MSG HERE” 即可。

    但oExcel.run却不支持返回值的,因此得另想办法。其实也简单,利用Sheet1的表格来存放返回值就可以了,EXCEL宏调用后将值写入Range中,而VBS则读取该Range的值即可,以此达到取得返回值之目的,^_^。下面以FindWindow为例:

    在API.XLS的Sheet1中加入如下代码:

    接下来由WinCC的VBS调用如下:

    oExcel.run却不支持返回值的,因此得另想办法。其实也简单,利用Sheet1的表格来存放返回值就可以了,EXCEL宏调用后将值写入Range中,而VBS则读取该Range的值即可,以此达到取得返回值之目的,^_^。下面以FindWindow为例: 

    API.XLSSheet1中加入如下代码:

    代码
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal
    lpClassName
    As String, ByVal lpWindowName As String) As Long
    Public Sub xlsFindWindow(WindowTitle As String)
    Dim hwnd As Long
    hwnd
    = FindWindow(vbNullString, WindowTitle)
    Sheet1.Range(
    "A1").Value = hwnd
    End Sub

    接下来由WinCC的VBS调用如下:

    代码
    Dim oExcelFile,oExcel,oWorkBook,oSheet
    oExcelFile
    = HMIRuntime.ActiveProject.Path + "\APIXLS\API.XLS"
    Set oExcel = CreateObject("Excel.Application")
    Set oWorkBook = oExcel.workbooks.OPen(oExcelFile)
    Set oSheet = oWorkBook.Sheets("Sheet1")
    oExcel.run
    "Sheet1.xlsFindWindow","WinCC-Runtime - "
    '#向FindWindow传递参数
    MsgBox oSheet.Range("A1").Value '#从Sheet中取得返回值
    oExcel.DisplayAlerts = False
    '#关闭EXCEL提示,因为我们对Sheet进行了修改,退出的时候会提示是否保存
    oWorkBook.Close
    Set oWorkBook = Nothing
    oExcel.quit
    Set oExcel = nothing

    3. 性能优化 

    大家都知道EXCEL调用起来是很慢的,尤其是每次CreateObject、workbooks.Open、oWorkBook.Close、oExcel.quit等等一整套程序下来,太浪费时间了,如果能像Public对象那样,自WinCC打开后就一直共享,自然要省事的多,而且也提高了执行效率。可以利用WinCC的DataSet对象来是Excel成为公共对象,关于DataSet详细使用见我的另一篇心得《WinCC V6使用DataSet创建全局对象.doc》。

    将以下代码放在起始页的OnOpen事件中:

    代码
    On Error Resume Next '#必加,否则GetObject会报错
    Dim oExcelFile,oExcel,oWorkBook,oSheet
    oExcelFile
    = HMIRuntime.ActiveProject.Path + "\APIXLS\API.XLS"
    'MsgBox oExcelFile
    Set oExcel = GetObject(,"Excel.Application") '#试图获取已经打开的EXCEL进程
    '
    MsgBox TypeName(oExcel)
    If VarType(oExcel)=vbEmpty Then '#如果为找到EXCEL进程,则由CreateObject新建
    Set oExcel = CreateObject("Excel.Application") '#新建EXCEL进程
    End If
    Set oWorkBook = oExcel.workbooks(“API.XLS”) '#试图获取已经打开的Excel文件
    '
    MsgBox TypeName(oWorkBook)
    If VarType(oWorkBook)=vbEmpty Then '#如未找到,则有Open打开Excel文件
    Set oWorkBook = oExcel.workbooks.OPen(oExcelFile) '#打开Excel文件
    'MsgBox oExcelFile & " Open Succeed!"
    End If
    Set oSheet = oWorkBook.Sheets("Sheet1")
    HMIRuntime.DataSet.Remove(
    "oExcel")
    HMIRuntime.DataSet.Add
    "oExcel",oExcel
    '#将oExcel保存到DataSet中,以供其它调用
    HMIRuntime.DataSet.Remove("oSheet")
    HMIRuntime.DataSet.Add
    "oSheet",oSheet
    '#将oSheet保存到DataSet中,以供其它调用

    上面的代码用于WinCC启动后首先检测是否有EXCEL进程,否则则新建EXCEL进程,以保证同时只有一个EXCEL.EXE在进程中,然后将API.XLS打开,并将oExceloSheet保存到DataSet中,以供其它调用。

    下面是WinCC任何页面中的调用方法:

    代码
    Dim oExcel,oSheet

    Set oExcel = HMIRuntime.DataSet("oExcel").Value

    Set oSheet = HMIRuntime.DataSet("oSheet").Value

    oExcel.run
    "Sheet1.xlsFindWindow","WinCC-Runtime - " '#向FindWindow传递参数

    MsgBox oSheet.Range("A1").Value

    由于省掉了CreateObject和quit,调用速度非常快。

    4.WinCC退出后关闭

    当然在WinCC退出时要想办法把刚开始打开的EXCEL进程给关闭掉,否则内存都给EXCEL吃掉了。

    标准函数里提供了OnDeactivateExecute,但这是C脚本,没有办法获取VBS的DataSet对象。只有在退出按钮中想办法了:

    代码
    '#结束EXCEL
    Dim oExcel
    Set oExcel = HMIRuntime.DataSet.Item("oExcel").Value
    oExcel.DisplayAlerts
    = False
    oExcel.quit
    Set oExcel = Nothing
    '#退出WinCC
    Dim WinCCODK
    Set WinCCODK = CreateObject("WinCCODK.Admin")
    WinCCODK.ExitWinCCEx
    &H1

    不过也可以利用OnDeactivateExecute来调用相关的VBS而达到关闭EXCEL进程的目的。

    代码
    void OnDeactivateExecute()
    {
    #define
    GetObject GetObject
    __object
    *oWSH=NULL;
    __object
    *HMIProj=NULL;
    char VbsPath[
    255];
    oWSH
    = __object_create("WScript.Shell");
    HMIProj
    = __object_create("CCHMIRTProject.HMIProject");
    sprintf(VbsPath,
    "%s\\OnDeactivateExecute.VBS",(char*)HMIProj->Path);
    //MessageBox(NULL,VbsPath,"test",MB_OK);
    oWSH
    ->Run(VbsPath);
    __object_delete(oWSH);
    __object_delete(HMIProj);
    }

    鉴于C脚本调用自动化对象比较难调试,而且OnDeactivateExecute已经没有办法使用GSC诊断,因此以上的C脚本仅为调用项目路径下的OnDeactivateExecute.VBS,剩下的工作交给它就可以了。

    代码
    '****该脚本用于WinCC退出时由标准函数OnDeactivateExecute进行调用***
    On Error Resume Next
    Dim oExcel,oWorkBook
    Dim fso,FilePath
    Set fso=CreateObject("Scripting.FileSystemObject")
    FilePath
    =fso.GetFolder(".").Path & "API.xls"
    'MsgBox FilePath
    Set oExcel = GetObject(,"Excel.Application")
    oExcel.DisplayAlert
    = False
    oExcel.WorkBooks(FilePath).Close
    oExcel.quit
    Set oExcel = nothing
    Set fso = Nothing

    相关资源

  • 相关阅读:
    Ruby+Appium+testunit实现app自动化demo
    C#+Selenium+Nunit实现Web自动化demo
    Ruby+Selenium+testunit web自动化demo
    Javascript+webdriverio实现app自动化demo
    Java+Appium+Junit实现app自动化demo
    Visual Studio 个人配置和插件
    git 如何处理合并时存在的子模块冲突
    数字货币回测框架准备篇:下载与清洗某安全量历史数据
    扩展期权定价模型到二元期权定价
    package.json
  • 原文地址:https://www.cnblogs.com/Godblessyou/p/1848225.html
Copyright © 2020-2023  润新知