您的当前位置:首页正文

WinCC VBS利用EXCEL调用Windows API函数

2022-06-17 来源:客趣旅游网
WinCC VBS利用EXCEL调用Windows API函数

By dcount 2008-11-1

前面已经讨论过利用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中加入如下代码:

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打开,并将oExcel和oSheet保存到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\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

因篇幅问题不能全部显示,请点此查看更多更全内容