之前写过一篇WinCC的电子签名与审计追踪,在那篇文章中使用报警操作记录生成审计追踪,后来测试VB脚本执行的情况,发现审计追踪中缺少执行该操作的用户名和计算机名,用C脚本执行倒是没有问题。在本文中再补充一个用InserAuditEntryNew生成审计追踪的方法,并且不再把电子签名和审计追踪做在一个函数里,将电子签名和审计追踪分成两个函数分别执行可以更灵活。
目录
生成审计追踪的方法
用脚本向Audit中添加记录有两种方法,一种方法是用WinCC提供的InserAuditEntryNew函数写入,另一种方法是生成属于“操作员输入消息”类型的报警消息,该报警消息同时也会记录到Audit中。
WinCC中的某些操作本身就会生成审计追踪记录,例如启动或关闭系统、登录用户等,这些操作生成的Audit记录的TargetName列是操作内容,而使用InserAuditEntryNew函数生成的记录在TargetName列的内容默认为VBScripting Runtime或CScripting Runtime,而操作内容只能记录在Reason列处。
在WinCC的电子签名与审计追踪一文中介绍了如何用“操作员输入消息”类型的报警生成把操作内容记录在TargetName列的审计追踪消息,之前以C脚本测试过这个方法可以达到要求,后来用VB脚本测试,审计追踪中ApplicationUser和ComputerName中是空的,即没有操作人和操作终端名称。如果要用VB脚本执行,这种方法是不能满足审计追踪要求的。在本文中再介绍使用InserAuditEntryNew函数生成审计追踪的方法。
VB脚本的电子签名和审计追踪
VB脚本的InsertAuditEntryNew函数
函数原型:
InsertAuditEntryNew(strOldValue, strNewValue, strOpComments, iComment)
参数:
参数 | 描述 |
strOldValue | 旧值 |
strNewValue | 新值 |
strOpComments | 注释 |
iComment |
0:将strOpComments参数的值作为注释记录到audit trial中 1:显示一个对话框,将对话框中输入的内容的作为注释记录到audit trial中 |
返回值:
- 整型值,含义未知,没有找到对此说明的官方文档。
VB脚本的审计追踪
把InserAuditEntryNew函数再封装为CreateOpMsg,添加一些参数。在VB全局脚本的项目模块中建立该函数。
函数原型:
Function CreateOpMsg(sSource, sInputMsg, OldValue, NewValue, sComments)
代码:
'---------------------------------------------------------------------------- ' 描述: ' 该函数向audit数据库中插入一条审计追踪记录, ' 在数据库的reason列写入"sSource: sInputMsg; sComments"字符串, ' 由三个字符串参数拼接而成。 ' 参数: ' sSource :该字符串表示这条记录的来源或类型 ' sInputMsg :该字符串表示这条记录的操作说明 ' OldValue :旧值 ' NewValue :新值 ' sComments :用户注释 ' 返回值: ' 与InsertAuditEntryNew函数返回值相同。 '---------------------------------------------------------------------------- Function CreateOpMsg(sSource, sInputMsg, OldValue, NewValue, sComments) CreateOpMsg = InsertAuditEntryNew(CStr(OldValue), CStr(NewValue), sSource&": "&sInputMsg&"; "&sComments, 0) '-------------------------------- ' 以下为通过报警生成审计追踪的代码 '-------------------------------- ' '创建操作员消息 ' dim myAlarm ' Set myAlarm = HMIRuntime.Alarms(12508142) ' MyAlarm.State = 5 ' '-------------------------- ' 'State Alarm Log Status ' '1 Came In ' '2 Went Out ' '5 Came in and comment ' '6 Gone and comment ' '-------------------------- ' myAlarm.Comment = sComments ' myAlarm.UserName = HMIRuntime.Tags("@NOP::@CurrentUser").Read ' myAlarm.ProcessValues(2) = OldValue ' myAlarm.ProcessValues(3) = NewValue ' myAlarm.ProcessValues(10) = sSource ' myAlarm.ProcessValues(7) = sInputMsg ' MyAlarm.Create End Function
VB脚本的电子签名
在VB全局脚本的项目模块中建立以下函数。
函数原型:
Function EsigDialog(Byref sComments, Byval bForcecomment, Byval sUserName)
代码:
'----------------------------------------------------------------------------------------- ' 描述: ' 执行该函数将弹出电子签名对话框, ' 并要求输入注释,可以设置是否要求强制注释, ' 注释内容通过sComments参数返回, ' 如果未给sUserName参数写入字符串,则使用当前登录的账户执行电子签名, ' 如果给sUserName参数写入了字符串,则将该字符串作为用户名执行电子签名。 ' 参数: ' sComments :引用一个字符串变量,注释内容将会写入到该变量中。 ' bForcecomment : ' False:可以不输入注释,即注释为空; ' True :必须输入注释。 ' sUserName :执行电子签名的用户名,如果该参数为空字符串,则使用当前登录的账户执行电子签名。 ' 返回值: ' -1:函数执行遇到错误 ' 1:电子签名通过 ' 2:用户取消了电子签名 ' 3:三次电子签名未通过 '------------------------------------------------------------------------------------------ Function EsigDialog(Byref sComments, Byval bForcecomment, Byval sUserName) Dim sDisplayedUser, sDomain sDomain = "" '如果加入了域,在此填写域名 '如果sUserName参数不为空,则使用提供的用户名做电子签名,否则使用当前登录的账户做电子签名 sUserName = Trim(sUserName) if sUserName <> "" then sDisplayedUser = sUserName Else sUserName = HMIRuntime.Tags("@NOP::@CurrentUser").Read sDisplayedUser = HMIRuntime.Tags("@NOP::@CurrentUserName").Read If sUserName = "" Then Select Case HMIRuntime.Language Case 2052 Msgbox "用户未登录,请登录后再执行!" Case 1033 Msgbox "Please log in before executing!" Case Else Msgbox "Please log in before executing!" End Select EsigDialog = -1 Exit Function End If End If '电子签名 Dim myEsig Dim ret Set myEsig = CreateObject("CCEsigDlg.ESIG") '强制注释 myEsig.forcecomment = bForcecomment ret = myEsig.showDialog(sUserName,sDisplayedUser,sDomain, HMIRuntime.Language, sComments) EsigDialog = ret End Function
VB脚本的电子签名和审计追踪示例
'--------------------------------------------------------------- ' 设定一个变量的新值,完成电子签名后,将修改的值记录到审计追踪 '---------------------------------------------------------------' Dim OldValue, NewValue Dim sComments NewValue = inputbox("设定加热温度") if Not IsNumeric(NewValue) then msgbox ("只能输入数字!") else if EsigDialog(sComments, False, "") = 1 then OldValue = HMIRuntime.Tags("tag1").Read HMIRuntime.Tags("tag1").Write NewValue Call CreateOpMsg("修改变量", "设定加热温度" , OldValue, NewValue, sComments) end if end if
VB脚本的写入变量新值的封装函数
在通过电子签名后,向一个变量写入新值,并记录到审计追踪,这个操作在WinCC中经常会使用。可以看到前面的代码稍有复杂,对这个过程再做一次封装在使用时会更加方便。
函数原型:
Function TagNewValueES(sSource, sInputMsg, sTagName, NewValue)
代码:
'------------------------------------------------------------------------------------ ' 描述: ' 执行电子签名,通过后向一个变量中写入新值,并将变量的新值和旧值记录到审计追踪, ' 在审计追踪的reason列中写入"sSource: sTagName: sInputMsg; sComments"字符串。 ' 参数: ' sSource :该字符串表示这条记录的来源或类型 ' sInputMsg :该字符串表示修改变量的操作说明 ' sTagName :变量名 ' NewValue :新值 ' 返回值: ' -1:函数执行遇到错误 ' 1:电子签名通过 ' 2:用户取消了电子签名 ' 3:三次电子签名未通过 '-------------------------------------------------------------------------------------- Function TagNewValueES(sSource, sInputMsg, sTagName, NewValue) Dim OldValue Dim sComments Dim iRet iRet = EsigDialog(sComments, False, "") if iRet = 1 then OldValue = HMIRuntime.Tags( sTagName ).Read HMIRuntime.Tags( sTagName ).Write NewValue Call CreateOpMsg(sSource, sTagName&": "&sInputMsg , OldValue, NewValue, sComments) end if End Function
C脚本的电子签名和审计追踪
C脚本的InsertAuditEntryNew函数
函数原型:
long int InsertAuditEntryNew(char* szOldValue, char* szNewValue, char* szOpComments, BOOL iComment, char* szReturnBuffer)
参数:
参数 | 描述 |
szOldValue | 旧值 |
szNewValue | 新值 |
szOpComments | 注释 |
iComment |
0:将strOpComments参数的值作为注释记录到audit trial中 1:显示一个对话框,将对话框中输入的内容的作为注释记录到audit trial中 |
szReturnBuffer |
引用一个字符串数组,含义不明,官方文档未对此说明 |
返回值:
- 整型值,含义未知,没有找到对此说明的官方文档。
C脚本的审计追踪
把InserAuditEntryNew函数再封装为CreateOpMsg,添加一些参数。在C全局脚本的项目函数中建立该函数。
函数原型:
long int CreateOpMsg(char* szSource, char* szMsg, char* szOldValue, char* szNewValue, char *szComments)
代码:
#include "apdefap.h" /*--------------------------------------------------------------------------------------------------- * 描述: * 该函数向audit数据库中插入一条审计追踪记录, * 在数据库的reason列写入"szSource: szMsg; szComments"字符串, * 由三个字符串参数拼接而成。 * 参数: * szSource :该字符串表示这条记录的来源或类型 * szMsg :该字符串表示这条记录的操作说明 * szOldValue :旧值 * szNewValue :新值 * szComments :用户注释 * 返回值: * 与InsertAuditEntryNew函数返回值相同。 *----------------------------------------------------------------------------------------------------*/ long int CreateOpMsg(char* szSource, char* szMsg, char* szOldValue, char* szNewValue, char *szComments) { char szCommentsBuffer[1024] = ""; char szReturnBuffer[1024] = ""; sprintf(szCommentsBuffer,"%s: %s; %s", szSource, szMsg, szComments); return InsertAuditEntryNew(szOldValue,szNewValue,szCommentsBuffer,0,szReturnBuffer); //Return-Type: long int }
C脚本的电子签名
在C全局脚本的项目函数中建立以下函数。
函数原型:
int EsigDialog(char* szComments,BOOL bForcecomment, char* szUserName)
代码:
#include "apdefap.h" /*--------------------------------------------------------------------------------------------- * 描述: * 执行该函数将弹出电子签名对话框, * 并要求输入注释,可以设置是否要求强制注释, * 注释内容通过szComments参数返回, * 如果未给szUserName参数写入字符串,则使用当前登录的账户执行电子签名, * 如果给szUserName参数写入了字符串,则将该字符串作为用户名执行电子签名。 * 参数: * szComments :引用一个字符串变量,注释内容将会写入到该变量中。 * bForcecomment : * False:可以不输入注释,即注释为空; * True :必须输入注释。 * szUserName :执行电子签名的用户名,如果该参数为空字符串,则使用当前登录的账户执行电子签名。 * 返回值: * -1:函数执行遇到错误 * 1:电子签名通过 * 2:用户取消了电子签名 * 3:三次电子签名未通过 *-----------------------------------------------------------------------------------------------*/ int EsigDialog(char* szComments,BOOL bForcecomment, char* szUserName) { char *Domain = ""; //如果加入了域,在此填写域名 char *szDisplayedUser = ""; int iRet = 0; VARIANT vtComment; __object* EsigDlg; char szUserNameBuffer[256]=""; char *strBegin = NULL; char *strEnd = NULL; /* 删除szUserName字符串两端空格 */ if (szUserName != NULL ){ strBegin = szUserName; while(*strBegin && isspace(*strBegin)) strBegin++; //如果是空格,首地址往前移一位,如果不是,则跳过该循环 strncpy(szUserNameBuffer,strBegin,255); strEnd = szUserNameBuffer + (strlen(szUserNameBuffer) - 1); while(*strEnd && isspace(*strEnd)) *strEnd-- = '\0'; //如果是空格,末地址往前移一位,并赋结束符 } /* 如果szUserNameBuffer参数不为空,则使用提供的用户名做电子签名,否则使用当前登录的账户做电子签名 */ if (strlen(szUserNameBuffer)>0) { szUserName = szUserNameBuffer; szDisplayedUser = szUserName; } else { szUserName = GetTagChar("@NOP::@CurrentUser"); //Return-Type: char* szDisplayedUser = GetTagChar("@NOP::@CurrentUserName"); //Return-Type: char* /* 判断用户是否登录 */ if (strlen(szUserName) == 0) { switch (GetLanguage()) { case 2052: MessageBox(NULL,"用户未登录,请登录后再执行!","Error",MB_SYSTEMMODAL|MB_OK); case 1033: default: MessageBox(NULL,"Please log in before executing!","Error",MB_SYSTEMMODAL|MB_OK); } return -1; } } /* 电子签名 */ EsigDlg = __object_create("CCESigDlg.ESIG"); if (!EsigDlg) { printf("Failed to create Picture Object\n"); return -1; } EsigDlg->forcecomment = bForcecomment; iRet = EsigDlg->ShowDialog(szUserName,szDisplayedUser,Domain,GetLanguage(),&vtComment); __object_delete(EsigDlg); /* 提取注释 */ if (szComments != NULL) sprintf(szComments,"%ls",vtComment.u.bstrVal); VariantClear(&vtComment); return iRet; }
C脚本的电子签名和审计追踪示例
#include "apdefap.h" void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { // WINCC:TAGNAME_SECTION_START // syntax: #define TagNameInAction "DMTagName" // next TagID : 1 // WINCC:TAGNAME_SECTION_END // WINCC:PICNAME_SECTION_START // syntax: #define PicNameInAction "PictureName" // next PicID : 1 // WINCC:PICNAME_SECTION_END /*------------------------------------------------------------------ * 设定一个变量的新值,完成电子签名后,将修改的值记录到审计追踪 *------------------------------------------------------------------*/ char szComments[2014]=""; double OldValue, NewValue; char sOldValue[512]=""; char sNewValue[512]=""; NewValue = 97; if (EsigDialog (szComments, FALSE, "") == 1 ) { OldValue = GetTagDouble("tag1"); SetTagDouble("tag1", NewValue); sprintf(sOldValue,"%f",OldValue); sprintf(sNewValue,"%f",NewValue); CreateOpMsg("修改变量", "设定加热温度", sOldValue, sNewValue, szComments); } }
C脚本的写入变量新值的封装函数
在通过电子签名后,向一个变量写入新值,并记录到审计追踪,这个操作在WinCC中经常会使用。可以看到前面的代码稍有复杂,对这个过程再做一次封装在使用时会更加方便。
向数值类型的变量写入新值
函数原型:
int DoubleTagNewValueES(char* szSource, char* szMsg, char* szTagName, double dNewValue)
代码:
#include "apdefap.h" /*--------------------------------------------------------------------------------------- * 描述: * 执行电子签名,通过后向一个变量中写入新值,并将变量的新值和旧值记录到审计追踪, * 在审计追踪的reason列中写入"szSource: szTagName: szMsg; szComments"字符串。 * 参数: * szSource :该字符串表示这条记录的来源或类型 * szMsg :该字符串表示修改变量的操作说明 * szTagName :变量名 * dNewValue :新值 * 返回值: * -1:函数执行遇到错误 * 1:电子签名通过 * 2:用户取消了电子签名 * 3:三次电子签名未通过 *-----------------------------------------------------------------------------------------*/ int DoubleTagNewValueES(char* szSource, char* szMsg, char* szTagName, double dNewValue) { char szComments[2014]=""; double dOldValue; char szOldValue[512]=""; char szNewValue[512]=""; char szbuffer[512]=""; int iRet = EsigDialog (szComments, FALSE, ""); if ( iRet == 1 ) { dOldValue = GetTagDouble(szTagName); SetTagDouble(szTagName, dNewValue); sprintf(szOldValue,"%f",dOldValue); sprintf(szNewValue,"%f",dNewValue); sprintf(szbuffer,"%s: %s", szTagName, szMsg); CreateOpMsg(szSource, szbuffer, szOldValue, szNewValue, szComments); } return iRet; }
向字符串类型的变量写入新值
函数原型:
int StrTagNewValueES(char* szSource, char* szMsg, char* szTagName, char* szNewValue)
代码:
#include "apdefap.h" /*------------------------------------------------------------------------------------- * 描述: * 执行电子签名,通过后向一个变量中写入新值,并将变量的新值和旧值记录到审计追踪, * 在审计追踪的reason列中写入"szSource: szTagName: szMsg; szComments"字符串。 * 参数: * szSource :该字符串表示这条记录的来源或类型 * szMsg :该字符串表示修改变量的操作说明 * szTagName :变量名 * szNewValue :新值 * 返回值: * -1:函数执行遇到错误 * 1:电子签名通过 * 2:用户取消了电子签名 * 3:三次电子签名未通过 *--------------------------------------------------------------------------------------*/ int StrTagNewValueES(char* szSource, char* szMsg, char* szTagName, char* szNewValue) { char szComments[2014]=""; char szOldValue[512]=""; char szbuffer[512]=""; int iRet = EsigDialog (szComments, FALSE ,""); if (iRet == 1 ) { sprintf(szOldValue,"%f", GetTagChar(szTagName) ); SetTagChar(szTagName, szNewValue); sprintf(szbuffer,"%s: %s", szTagName, szMsg); CreateOpMsg(szSource, szbuffer, szOldValue, szNewValue, szComments); } return iRet; }