wincc的n个经典问题解答之三
41:用C编程解决授权点数不够用的问题(acsun提供)
当需要的工艺参数超过WinCC版本限制的Tag数目,可以用C语言编程实现多个工艺参数打包成一个Tag传送.例如某个配料称重系统有146个参数超过了WinCC的128个Tag的限制就可以用C语言编程决这一问题而不需要购买更高的授权.
基本思想就是把多个参数在下位机内存中连续排列然后在WinCC中定义一个Tag它的长度是多个参数之和取得这个Tag后编程将其分成多个参数
例如下位机有两个参数LTN44001和LTN44023都是16位整数分别存放在DD99.DW146和DD99.DW148
在WinCC中定义一个外部Tag命名为PackageTag类型为32位整数并联地址为DD99.DBD146再定义两个内部tag名为LTN44001和LTN44023在 Global Script全局脚本中C语言编程如下 Union {
Long Dword Int Word[2] }union
Union.Dword=GetTagDword(\"PackageTag\") SetTagWord(\"LTN44001\SetTagWord(\"LTN44023\
这样两个参数LTN44001和LTN44023就通过一个Tag传送上来了理论上只要下位机内存足够可以传送任意数量的参数而不受WinCC版本外部Tag数目的限制.
42:如何在WinCC里用C语言调用SQL语言? 1、创建一个SQL文件。
此文件在ISQL中创建,文件内容是所希望执行的SQL语句。
2、在WinCC的C Script中编写程序调用此SQL文件,如以下程序所示: #i nclude \"apdefap.h\"
void OnLButtonDown(char* lpszPictureName,
char* lpszObjectName,
char* lpszPropertyName,
UINT nFlags, int x, int y)
{
char*a=\"C:\\\\SIEMENS\\\\Common\\\\SQLANY\\\\ISQL-q-b-c
UID=DBA;PWD=SQL;DBF=E:\\\estsql\\\estsqlRT.DB;
DBN=CC_testsql_99-12-03_12:48:26R;
READ
E:\\\estsql\\\est.sql\";
printf(\"%s\\r\\n\
ProgramExecute(a); }
下面是一个简单的SQL文件内容:
select * from pde#hd#t#test;
output to E:\\\est2.txt FORMAT ascii 注意:文件名及路径中不要带空格。
43:如何整点启动归档?
在\"Global Script\"下的Project functions编写函数:cyclicarchive
BOOL cyclicarchive() {
#pragma code (\"kernel32.dll\");
void GetLocalTime (SYSTEMTIME* lpst);
#pragma code();
SYSTEMTIME time;
Int t1;
GetLocalTime(&time);
t1=time.wMinute;
if(t1==00) {
SetTagBit(\"startarchive\
return(BOOL)(GetTagBit(\"startarchive\")); } }
在Tagloging中的\"Properties of process tag\"中的\"Archive Tag\"tab下的Archiving type选择Cycle-selective,在\"Event\"标签下的\"Start Event\"内选择cyclicarchive函数。
44:如何在按键组合被禁用的情况下,从WinCC运行环境进入WinCC Control Center? 最好是做一个按钮,该按钮需要用用户权限保护,在该钮中编写如下C-action:
低于WinCC 5.0版本:
#pragma code (\"user32.dll\");
BOOL SetForegroundWindow(HWND);
#pragma code();
HWND handle;
handle=FindWindow(\"MCPFrameWndClass\
If (!SetForegroundWindow(handle))
Printf (\"\\r\\n SetForeground fails\");
WinCC 5.0版本以及更高的版本:
#pragma code(\"user32.dll\");
BOOL SetForegroundWindow(HWND);
#pragma code();
HWND handle;
handle=FindWindow(\"WinCCExplorerFrameWndClass\
If (!SetForegroundWindow(handle))
Printf (\"\\r\\n SetForeground fails\");
45:WinCC如何实现鼠标OnMouseOVer事件?
用WINDOWAPI函数GetCusorPos获取当前鼠标位置,用GetWindowRect函数获取窗口位置,两值相减得鼠标在WINCC frame上的相对位置。用全局脚本(设定为1s定时刷新),然后获取要OnMouseOver事件的物体的位置,并与鼠标位置相比较,如一致则触发自己定义的动作。
#include \"apdefap.h\" int gscAction( void ) {
#pragma code(\"user32.dll\");
BOOL GetCusorPos(POINT lpPoint); //获取鼠标的位置(绝对位置-对应屏幕分辨率) BOOL GetWindowRect(HWND hwnd,LPRECT lpRect); //获取窗体位置 #pragma code(); POINT pPos; RECT rRec; HWND hwnd; BOOL bRet,bRet2;
long lLeft,lTop,lWidth,lHeight; long lX,lY; char szStr[100];
hwnd=FindWindow(NULL,\"WinCC-Runtime - \"); //如语言为中文应为\"WinCC 运行系统-\"
if (hwnd==0) {printf(\"\\r\\nError! WinCc Handle is %d\
bRet=GetCursorPos(&pPos); if (bRet==0) goto over;
bRet2=GetWindowRect(hwnd,&rRec); if (bRet2==0) goto over;
lX=pPos.x-rRec.left; //鼠标 对{置 lY=pPos.y-rRec.top; //鼠标 位置
//如果为非全屏模式,需将上述数值中的高height判断减去标题栏的宽度 //printf(\"The Current Cusor Pos is x:%d,y:%d\\r\\n\
//printf(\"The Cusor Pos in Window is x:%d,y:%d\\r\\n\ lLeft=GetLeft(\"NewPdl0.Pdl\ //Return - Type :long int lTop=GetTop(\"NewPdl0.Pdl\ //Return - Type :long int lWidth=GetWidth(\"NewPdl0.Pdl\ //Return - Type :long int lHeight=GetHeight(\"NewPdl0.Pdl\ //Return - Type :long int
if ((lX>=lLeft)&&(lY>=lTop)&&(lX<=lLeft+lWidth)&&(lY<=lTop+lHeight)) {
sprintf(szStr,\"%d,%d\
SetText(\"NewPdl0.Pdl\ //Return - Type :char* }
//printf(\"The Text1 Pos is x:%d,y:%d\\r\\n\ over: return 0; }
46:如何实现ASP与WinCC V6数据库sql server 2000的连接?
WinCC V6用ODK获取DSN名,{后生成网址字符串,再用shellExecuteA函数打开网页 //---------------------------------------------------------------------------------- #pragma code(\"shell32.dll\")
long ShellExecuteA(HWND,LPCTSTR,LPCTSTR,LPCTSTR,LPCTSTR,int); #pragma code()
char dsnStr[100]; HWND hwnd;
sprintf(dsnStr,\"http://dcount/test.asp?dsnStr=%s\ //Return-Type: LPCTSTR printf(\"\\r\\n%s\
hwnd=FindWindow(NULL,\"WinCC - Runtime \");
ShellExecuteA(hwnd,\"open\ //-------------------------------------------------------------------------------------
ASP方面需要注意的是连接字符串的形式与普通acess ODBC不太一样,而且需要用户名和密码
由于WINCC封装的sa用户的密码暂时不知道,所以必须用SQL Server EnterPrise Manager建立自己的用户,添加system Administrator权限就可以了!否则会出现错误提示 Microsoft OLE DB Provider for SQL Server 错误 '80040e4d' Login failed for user 'sa'.
'--------------------------------------------------------------------------------------
dsnStr=request(\"dsnStr\")
set conn=server.createobject(\"adodb.connection\") set rs=server.createobject(\"adodb.recordset\") conn.Provider = \"sqloledb\"
conn.open \"Server=DCOUNT\\WINCC;Database=\" & dsnStr & \";UID=dcount;pwd=;\" rs.open \"select * from test\ response.write rs.recordcount do while not rs.eof
response.write rs(\"f1\") & \"---\" & rs(\"f2\") & \"---\" & rs(\"f3\") rs.movenext loop rs.close conn.close
47:如何在退出WINCC监控时直接关闭电脑? 1.利用动态向导
2.在脚本中加入 DMExitWinCCEx (DM_SDMODE_SYSTEM);也可以
48:如何通过WINCC API函数读出当前报警消息?
1、使用GMsgFunction中读出当前报警信息的ID(dwMsgNr);
2、使用MSRTGetMsgCSData函数读出该报警信息ID对应文本库TEXTLIB中的文本ID(dwTextID1);
3、使用MSRTGetMsgText函数读出该文本ID的文本。 信息到达处理:如果读取文本成功,则置文本变量MSG。
信息离去处理:如果MsgNr与上一次相同,则复位MSG,如果不是,则继续保持信息。 具体函数说明请看ODK文档
BOOL GMsgFunction( char* pszMsgData) {
#pragma code(\"msrtcli.dll\") #i nclude \"msrtapi.h\" #pragma code();
MSG_TEXT_STRUCT tMeld; MSG_CSDATA_STRUCT sM; CMN_ERROR err; BOOL bRet;
DWORD dwTextID1; DWORD dwMsgNum; char szMsg[255];
#define TAG_MSG \"MSG\"
MSG_RTDATA_STRUCT mRT;
memset( &mRT, 0, sizeof( MSG_RTDATA_STRUCT ) );
if( pszMsgData != NULL ) {
printf( \"Meldung : %s \\r\\n\ sscanf( pszMsgData, \"%ld,%ld,%04d.%02d.%02d,%02d:%02d:%02d:%03d,%ld, %ld, %ld, %d,%d\ &mRT.dwMsgNr, // Meldungsnummer
&mRT.dwMsgState, // Status MSG_STATE_COME, .._GO, .._QUIT, .._QUIT_SYSTEM &mRT.stMsgTime.wYear, // Tag &mRT.stMsgTime.wMonth, // Monat &mRT.stMsgTime.wDay, // Jahr &mRT.stMsgTime.wHour, // Stunde &mRT.stMsgTime.wMinute, // Minute &mRT.stMsgTime.wSecond, // Sekunde &mRT.stMsgTime.wMilliseconds, // Millisekunde
&mRT.dwTimeDiff, // Zeitdauer der anstehenden Meldung &mRT.dwCounter, // Interner Meldungsz?hler &mRT.dwFlags, // Flags( intern ) &mRT.wPValueUsed, &mRT.wTextValueUsed );
//**************************************************************************************code for dcount
if (mRT.dwMsgState==MSG_STATE_COME)//信息到达处理 {
dwMsgNum=mRT.dwMsgNr;
printf(\"\\r\\nThe Alarm Message No is %d !\\r\\n\ bRet=MSRTGetMsgCSData(dwMsgNum,&sM,&err); if (bRet==TRUE) {
dwTextID1=sM.dwTextID[0]; printf(\"\\r\\nThe TextID of The MessageNr %d is %d !\\r\\n\
bRet=MSRTGetMsgText(1,dwTextID1,&tMeld,&err); if (bRet==TRUE) {
sprintf(szMsg,\"%s\
printf(\"\\r\\nThe Text of TextID %d is %s !\\r\\n\ } }
}
if (mRT.dwMsgState==MSG_STATE_GO)//信息离去处理 {
dwMsgNum=mRT.dwMsgNr;
if (dwMsgNum==GetTagDWord(TAG_MSG_NR)) SetTagChar(TAG_MSG,\"\"); }
//**************************************************************************************code for dcount
// Meldungsdaten einlesen
// Prozesswerte lesen, falls gew???????§???1nscht }
printf(\"Nr : %d, St: %x, %d-%d-%d %d:%d:%d.%d, Dur: %d, Cnt %d, Fl %d\\r\\n\" ,
mRT.dwMsgNr, mRT.dwMsgState, mRT.stMsgTime.wDay, mRT.stMsgTime.wMonth, mRT.stMsgTime.wYear, mRT.stMsgTime.wHour, mRT.stMsgTime.wMinute, mRT.stMsgTime.wSecond, mRT.stMsgTime.wMilliseconds, mRT.dwTimeDiff, mRT.dwCounter, mRT.dwFlags ) ;
SetTagChar(TAG_MSG,szMsg);
return( TRUE ); }
49:如何实现用户登陆日志(wincc中用c脚本实现?)( 柳树成林原创) 用户登陆日志:(包括用户的登陆退出信息,以便查询在什么时间段是哪个用户在使用这个监控软件)
#i nclude \"apdefap.h\"
int gscAction( void ) {
#pragma code(\"kernel32.dll\")
VOID GetLocalTime(LPSYSTEMTIME lpSystemTime); #pragma code()
char* username; char buf[128];
static char preuser[128]; unsigned a,b,c,d,e,f; FILE* fp;
SYSTEMTIME sysTime;
//读取系统时间,并且复制给变量a,b,c,d,e,f GetLocalTime(&sysTime);
a=sysTime.wHour; b=sysTime.wMinute; c=sysTime.wSecond; f=sysTime.wYear; e=sysTime.wMonth; d=sysTime.wDay;
//得到当前用户名称
username = GetTagChar(\"@CurrentUser\"); fp= fopen(\"c:\\\\wincclog.txt\
if(strcmp(username, preuser)!=0) //如果当前用户名称和前一个用户名不同 {
if((strcmp(username, \"\") != 0)&&(strcmp(preuser, \"\") == 0)) //如果当前用户名称不空同时前一个用户名为空
{
sprintf(buf, \"用户:%s\登陆时间是:\ %d-%d-%d,%d-%d-%d\\n\username,a,b,c,d,e,f);
fputs(buf, fp); } else {
if((strcmp(username, \"\") == 0)&&(strcmp(preuser, \"\") != 0)) //如果当前用户名称为空同时前一个用户名不空
{
sprintf(buf, \"用户:%s\退出时间是:\ %d-%d-%d,%d-%d-%d\\n\preuser,a,b,c,d,e,f);
fputs(buf, fp); }
else {
sprintf(buf, \"用户:%s\退出时间是:\ %d-%d-%d,%d-%d-%d\\n\preuser,a,b,c,d,e,f);
fputs(buf, fp);
sprintf(buf, \"用户:%s\登陆时间是:\ %d-%d-%d,%d-%d-%d\\n\username,a,b,c,d,e,f);
fputs(buf, fp); } } }
strcpy(preuser, username); fclose(fp);
return 0; }
50:在wincc画面编辑器里注册的OCX控件,由于开发时没有考虑到wincc标准控件中具备层次哪个属性!所以不能够通过画面编辑器里的菜单进行设置OCX控件的层次关系!
建议不要把wincc中注册的OCX控件和wincc本身的标准控件重叠放置,否则wincc本身的标准控件将被覆盖!
因篇幅问题不能全部显示,请点此查看更多更全内容