当前位置: 首页 > 编程日记 > 正文

TI IPNC Web网页之网页修改教程

web网页程序修改

打开gStudio之后,点击菜单栏中Help->Contents。先把这个诡异的编程语言看一遍吧。这里搬一些东西出来。

GoDB简介

161208408232554.png

161208559954686.png

从第一副图片中,我们可以看出,从源文件到可执行文件的过程。

从第二幅图我们可以了解到GoDB是如何跨平台的。

编程语言的话:

GBasic is a variant of the Basic Language included in GoDB platform as the scripting language.

这种编程语言大小写不区分,真是编程界的一朵奇葩。

GBasic编程语言

GBasic程序通常是有一个frm文件和与之名字相同的bas文件。比如说当HOME.frm被加载时,HOME.bas就会被执行。

  • GBasic中的字符串变量名以$结尾。
  • 如果没有$的变量则认为是数值变量
  • GBasic有两种对象(object),一种是Form Field Objects(可理解为Visual Studio中的rc文件),另外一种是数据库(专业版才能使用)
  • 在GBasic中调用From对象方式是用#对象名
  • GBasic中有三种变量范围,全局,局部和当前页面。
    其中变量名以~开头的是全局变量,你可以在工程的任何地方访问这个变量。没有以~开头的变量并且声明在Sub或者Function之外的,则为页面变量,声明在Sub或者Function内部的则是局部变量。
  • 像其它任何语言一样,GBasic也可以将针对多行代码进行封装。GBasic提供Subroutines和Functions这两种方式,前者没有返回值,后者需要返回值。如果要直接调用Subroutines,你需要在其前面家call,比如说call subname,而Functions的调用则不用。
  • Functions返回值的做法是赋值给函数名。

GBasic自带了很多封装好的函数,这些函数如何用,请看Help。

GStudio这个IDE像Visual Stduio一样,支持控件的事件触发(按钮按下,编辑框改变etc.)这些事件称之为控件的事件,还有另外一种事件叫做Global Event

具体查看Help中的GBasic Reference->Global Event。这里稍微介绍下

form_load当frm文件加载首先执行的是这个Sub。
form_notify当收到服务器反馈时自动调用,此时在用GetMessage获取消息内容..
form_timer,定时器触发时调用此Sub,通常使用settimer(1000)来使能定时触发。

所以一般阅读GoDB工程代码一般先从每个bas文件的form_load开始看起。

Debug

  • 在GUI的下拉菜单中,保证当前选中的是"DEBUG"模式;
  • 按F7编译工程,按F5会编译和启动项目;
  • 保证你在"Win32_Debug"文件夹中有"ip.txt"文件,这个是用于用户登录的。

Release

  • Debug/ Release下拉菜单中选中Release
  • 在View-option在选项卡Build中在Make Read-Only BDB选中
  • 在文件夹Win32_Release中找到gIPNC-ro.bdb
  • 使用以下命令生成gIPNC-ro.gz

gIPNC工程分析

我们做的是在原有基础上添加东西,修修补补,谁要是有精力就从头开始弄吧。

bas和frm和inc一一对应,bas为执行文件,inc为头文件,frm为form文件,相当于Visual Studio中的rc文件。

还是先分析流程吧。

首先当然是登录界面,那就是对应logon.bas和auth.bas,首次登录执行的auth.bas文件,而用户刷新过程中执行的logon.bas文件。

关于logon.bas

readprofile("PAGENAME",pageName$)
...
readprofile("IPNC",loginDet$)
...

首先读取变量名为IPNC和PAGENAME的profile,如果读取得到那么就将读取到的用户名和密码填充到用户名编辑框和登录编辑框(这就是记住密码功能),调用dwnldIniFile函数进行Http请求,请求内容是ip地址/ini.htm,这样如果认证通过,那么此时已经把所有关键字及其内容保存到~responseData$全局环境变量上。获取失败则弹出用户或密码错误。读取profile错误,则加载auth.frm。

我们知道,TI IPNC除了用户验证登录之外还有区分用户权限,所以在成功调用dwnldIniFile调用getUserAuthority获取当前用户的权限,获取失败弹出错误信息,成功并且PAGENAME的值为LOGIN则加载auth.frm,否则直接进入liveVideo.frm

温馨提示,仔细研究下writeprofile函数,你就知道如何做到真正的记住密码。

温馨提示,GetIPAddress()是进行调试的关键。

分析auth.bas不难发现,无非就是。先将读取到的IPNC变量的值进行填充,然后这个文件主要的逻辑就是cmdSubmit_Click这个按钮按下的事件处理函数了。先进行输入验证,然后是登录验证,也是调用dwnldIniFile进行认证getUserAuthority。最后成功加载livevideo.frm,并写PAGENAME的profile。

** 几个比较关键的文件 **

这个工程里面有几个文件是比较重要(特殊的文件)的那就是leftmenu.bas,functions.inc,defines.inc,common.inckeywords.inc

  1. 其中leftmenu.bas是网页侧边栏的执行文件,添加,删除子菜单就修改这个文件。
  2. functions.inc里面定义了众多函数,大部分是网页keyword获取和设置的函数。
  3. defines.inc文件定义了一些关键数字,比如说侧栏菜单(主菜单,子菜单)多少个,比如关键字最多有多少个,有时候一些莫名其妙的错误就是由于这个文件上的数字没对上引起的。
  4. common.inc定义了一些通用函数,比如编辑框可以输入哪些字符,不可以输入哪些字符(CheckKey),产生Request Header(generateauthHeader)。
  5. keywords.inc,这个仅在functions.inc中被包括。这个文件其实不太重要,作用仅仅是用于显示获取或设置关键字时的错误信息而已。

logon.bas和auth.bas他们都包括了functions.inc,defines.inc,common.inc。而其它的主页面除了这个三个文件之外,还包括leftmenu.bas,这样的效果就是将侧边栏和各个form的网页叠加起来。

GBasic是从头到尾顺序执行的,所以每个bas文件先执行Sub或者functions之外的语句之后,然后再执行form_load事件,由于先包括了leftmenu.bas,所以会先执行leftmenu.bas里面的内容,而每个frm页面都包括了leftmenu.frm文件。这样就加载了侧边栏。

leftmenu负责触发加载各个页面。

添加删除侧边栏菜单

161209198549595.png

这里只说怎么加,不讨论怎么建页面。

打开leftmenu.bas

dims ~menuArray$(MAXMAINMENU+MAXSUBMENU+3)
dims menuOffImg$(MAXMAINMENU) = ("!camera_Off.bin","!users_Off.bin","!settings_Off.bin","!maintanance_off.bin","!support_off.bin")
dims ~menuOnImg$(MAXMAINMENU) = ("!camera_On.bin","!users_On.bin","!settings_On.bin","!maintanance_on.bin","!support_on.bin")
dims ~urlMainArray$(MAXMAINMENU) = ("!liveVideo.frm", "!addusers.frm","!videoImageSettings.frm","!maintenance.frm","!supportScreen.frm")
dims ~urlSubArray$(MAXSUBMENU) = ("!videoImageSettings.frm","!videoAnalyticsSetting.frm","!DMVAeventMonitor.frm","!display_settings.frm", "!audioSetting.frm","!setDateTime.frm", "!NetworkSettings.frm", "!alarmSettings.frm", "!class.frm","!storageSetting.frm")dimi dmvaEnable#imgselected.hidden = 1 
loadMenuCaptions()
....

上面是我修改过的。其中比较关键的是几个宏定义的定义,如果你要修改,请算好侧边栏的个数,然后修改在defines.inc中的数值。bin文件是主菜单的对应的图片,关于图片后面才说,frm就是对应的页面啦,算好顺序...

  1. 如果要增加页面,则在leftmenu.frm中增加一个ReadOnly控件,然后NAME必须为rosubmenu,value为空,背景那些参照已有的..你会发现有好几个ReadOnly都叫做rosubmenu,然后这个ide就自动就其他们的name改为类似数组的样子..rosubmenu[0],而程序里面也是如此引用。
  2. 修改字符串数组~URLsUBaRRAY$,将建立好的FRM的文件名添加到末尾
  3. 修改子菜单数量maxsubmenu和leftmenuctrls(在DEFINE.INC中定义).各加1
  4. 修改子菜单名字,修改MENUcAPTIONS.LAN文件,这个文件前面5个是主菜单,后面是子菜单的名字
  5. BUG.将ARRmOUSEpOS(14, 4)改成ARRmOUSEpOS(maxmainmenu+maxsubmenu, 4),否则会出现数组越界
  6. 子菜单对应的页面的BAS文件必须包括两个函数savepage()和chkValueMismatch(),否则会报错..

当然leftmenu大部分菜单鼠标点击时鼠标的触发事件,也就是加载相应的页面。当然还有什么图标排列,音视频开关等处理...

另外值得注意的是:子菜单中有可能有一两个页面是默认隐藏的,某种条件触发下才显示。比如Live Video页面那个Example的下拉框就是一个触发条件,另外如果用户权限不同,子菜单显示的个数也有所不同,这些逻辑都在leftmenu.bas中。

子页面流程分析

IPNC网页默认几个页面,大部分都是传统的表单页面,无非就是些CheckBoxEditCommonBox之类的控件,加载页面的时候,就是获取服务器上对应的控件的值然后填充进去,保存页面的时候,则是发送http请求到web服务器进行保存然后重新获取更新。

一般来说一个控件对应一个关键字。

我们先从对应页面的form_load看起,然后看savepage,然后看各个控件触发事件..其它全局事件。

我们拿声音设置页面为例,对应的文件是audiosetting.basaudiosetting.frm文件。

Sub Form_Loaddimi retValretVal = loadIniValues()if ~maxPropIndex = 0 then msgbox("无法加载初始配置",0,"错误",3)loadurl("!auth.frm")endifcall displayControls(LabelName$,XPos,YPos,Wdh,height)call loadInitialValues()    showSubMenu(0,1)setfocus("rosubmenu[4]")selectSubMenu() setfocus("chkenableaudio")call chkenableAudio_Click                                   'TR-19getimagefile(sliderImage$,"!slider_but.jpg")#lblsuccessmessage$ = ""                                    'TR-35End Sub

retVal = loadIniValues()

这是个关键函数,这个函数里面请求http://ip/ini.htm获取所有关键字的值,如果获取失败了,就提示错误。在loadIniValues函数中,有个字符串数组非常关键,每次添加新的关键字都必须修改这个字符串在后面添加新的关键字。keywords$

网页在functions.inc中的loadIniValues()中解析得到这些值将这些属性和对应的放分别放到字符串数组~iniProperties$和iniPropValues$中.
值得注意的是在放入~iniProperties$之前,在每个属性名之前加了字母"g".

每个页面的form_load都会在一开始调用这个函数

call loadInitialValues()

这个函数,也是非常典型,几乎每个页面都会做类似的处理(可能函数名字不同或者没用函数),作用是获取当前页面关键字的值然后填充到控件里面。

然后这里基本上都用到functions.inc中"get"开头的一些函数,这些函数参数不同,都是处理流程一致,都是分析~iniPropValues$这个全局变量然后取出对应的关键字的值。

retVal = getAudioSetting(enableAudio,audioMode,inputVolume,_encoding,sampleRate,bitRate, _alarmLevel,outputVolume)
'functions.inc中定义
function getAudioSetting(byref dimi enableAudio, byref dimi audioMode, byref dimi inputVolume, _byref dimi encoding, byref dimi sampleRate, byref dimi bitRate, _byref dimi alarmLevel, byref dimi outputVolume)'TR-26                   dims varName$(8)  = ("enableAudio","audioMode","inputVolume", _"encoding","sampleRate","bitRate", _"alarmLevel","outputVolume") dims propName$(8) = ("gaudioenable","gaudiomode","gaudioinvolume", _"gencoding","gsamplerate","gaudiobitrate", _"galarmlevel","gaudiooutvolume")dims tempVal$(8)dimi i,retValretVal = getiniValues(propName$,tempVal$)   if retVal = 0 thenfor i= 0 to ubound(tempVal$)    {varName$(i)} = strtoint(tempVal$(i))       nextendifreturn retVal   End Function

所以当你添加新的关键字时,做法可以是在原有函数基础增加参数。也可以按照里面的这些函数的形式和逻辑重新定义一个新的函数...

下面介绍另外一个重要函数,那就是savepage函数,记住不管你页面是否需要保存,都必须存在这个函数。正如前面一小节所说......

savepage函数里面重要是使用functions.inc中"set"开头的一些函数。这些函数参数不尽相同,但是逻辑相同,都是通过发送http请求设置关键字的值。

savepage函数一般还会做控件输入值有效的检测,错误成功信息显示等处理...

/*一般实在保存按钮的事件响应函数中调用savepage函数*/
Sub cmdsave_Click   if canReload = 1 thensavePage()      end if
End Sub
Sub savePage()'Validate user input controls valuesiff validatemodecontrols() = 0 then return  dimi retVal,i' TR-26 set values to cameraretVal = setAudioSetting(#chkenableaudio,#drpaudiomode,atol(#sldaudioinput$),_#drpencoding,#drpsamplerate,#drpbitrate,_#sldalarmlevel,atol(#sldaudiooutput$))saveSuccess = retValtempX = #lblsuccessmessage.x'Based on reload flag wait for the camera to restartif getReloadFlag() = 1 then                             'TR-45              #lblsuccessmessage.style = 128#lblsuccessmessage.x = #lblsuccessmessage.x + #lblsuccessmessage.w/3canReload = 0animateCount = 1call animateLabel("lblsuccessmessage","参数更新中")else // If Reload animation is not requiredcanReload = 1end ifif canReload = 1 Then   //Do the remaining actions after reload animation is donecall displaySaveStatus(saveSuccess)     end if  
End Sub
function setAudioSetting(dimi enableAudio, dimi audioMode, dimi inputVolume, _dimi encoding, dimi sampleRate, dimi bitRate, _dimi alarmLevel, dimi outputVolume)    dimi retdims value$dims responseData$' TR-26value$ = "audioenable="+enableAudio+"&audiomode="+audioMode+"&audioinvolume="+inputVolume+_"&encoding="+encoding+"&samplerate="+sampleRate+"&audiobitrate="+bitRate+_"&alarmlevel="+alarmLevel+"&audiooutvolume="+outputVolumepprint value$        ret = setProperties(value$, responseData$)  if ret > 0 thendims propName$(8) = ("gaudioenable","gaudiomode","gaudioinvolume", _"gencoding","gsamplerate","gaudiobitrate", _"galarmlevel","gaudiooutvolume")dims propVal$(8)propVal$(0) = enableAudiopropVal$(1) = audioModepropVal$(2) = inputVolumepropVal$(3) = encodingpropVal$(4) = sampleRatepropVal$(5) = bitRatepropVal$(6) = alarmLevelpropVal$(7) = outputVolume~errorKeywords$ = ""~errorKeywords$ =  chkRetStatusAndUpdate$(responseData$,propName$,propVal$)if len(~errorKeywords$) > 0 thenreturn -10elsereturn retendif       endif return ret              End Function

跟踪到里面去,不难发现,实际上就是发送这样形式的Http请求:

vb.htm?keyword1=xx&keyword2=xxx

当增加新的关键字时,可以仿照这些set开头函数重新定义一个新的函数,也可以在原有基础上扩充。

GoDB端添加关键字的流程

这里介绍在GoDB端添加关键字的流程。我们忽略boa端代码的修改,所以修改完之后,既不能获取到这个关键字也无法设置成功。

现在举添加rtmp功能的例子..

页面如下,在网络/端口设置页面添加一个checkbox和一个edit,这就对应了两个关键字,关键字名字分别为rtmp_enrtmp_url(随意)

161209510269972.png

还是从from_load开始,还是从加载控件默认值的函数开始...

call ShowDefaultValues()

在这个Sub内:
dimi rtmp_en
Dims rtmp_url$

然后我们选择扩充已有的函数

retVal=getSNTPRTSPDetails(sntpServer$, multiCast,rtmp_en,rtmp_url$)

/*在functions.inc中定义*/
function getSNTPRTSPDetails(byref dims sntpServer$,byref dimi multiCast,byref dimi rtmp_en,byref dims rtmp_url$)dims varName$(4)  = ("sntpServer$","multiCast","rtmp_en","rtmp_url$")dims propName$(4) = ("gsntpip","gmulticast","grtmp_en","grtmp_url")dims tempVal$(4)dimi i,retret=getiniValues(propName$,tempVal$)if ret>=0 thenfor i= 0 to ubound(tempVal$)if i=1 or i=2 then{varName$(i)} = strtoint(tempVal$(i))           else {varName$(i)} = tempVal$(i)             endifnextendifreturn ret End Function

你对比下原始函数就知道我修改了哪里..

接着我们修改functions.inc中的loadIniValues函数,将rtmp_enrtmp_url添加到keywords$字符串后面

/*....*/keywords$ +=",aviformat,aviformatname,aviduration,avidurationname,reloadtime,qpinit1,qpinit2,qpinit3"_",videocodeccombo,videocodeccomboname,streamname1,streamname2,streamname3"_",localdisplayname,sdinsert,reloadflag,dmvaenable,minnamelen,maxnamelen,minpwdlen,maxpwdlen,maxaccount"_",bkupfirmware,display_mode,ppt_sw_en,ppt_sw_sensitivity,ppt_sw_interval_time,channel_id,psname,piname,ch_id_name"_",file_size,video_long,brightness2,contrast2,saturation2,sharpness2,brightness3,contrast3,saturation3,sharpness3,brightness4,contrast4,saturation4,sharpness4"_",language,ftp_upload_option,ftp_upload_time,trackip,cloudip,serverenable,singlecodecres,rtmp_en,rtmp_url"

接着我们修改keywords.inc文件,将这两个关键字添加到cameraKeywords$关键字后面。"|"右面是错误提示信息,合理填写即可。

cameraKeywords$ += ",display_mode|Display mode,ppt_sw_en|PPT Switch Enable,ppt_sw_interval_time|PPT Switch interval Time,"_",ppt_sw_sensitivity|PPT Switch sensitivity,channel_id|main display channel,language|language,trackip|track ip,cloudip|cloudip,"_",serverenable|Upload to server,singlecodecres|resolution for single stream,rtmp_en|rtmp enable,rtmp_url|rtmp url"

接着,我们修改savepage函数。

retVal = setSNTPRTSPDetails(#txtsntpserver$, #chkrtspmulticast,#chkrtmp,#txtrtmpurl$)

这里传入的参数是直接将对象的值传入..

function setSNTPRTSPDetails(dims sntpServer$,dimi multiCast,dimi rtmp_en,dims rtmp_url$)dimi retdims SNTPRTSPDetails$dims responseData$SNTPRTSPDetails$="sntpip="+sntpServer$+"&multicast="+multiCast+"&rtmp_en="+rtmp_en+"&rtmp_url="+rtmp_url$       ret = setProperties(SNTPRTSPDetails$, responseData$)if ret >= 0 thendims propName$(4) = ("gsntpip","gmulticast","grtmp_en","grtmp_url")dims propVal$(4)propVal$(0) = sntpServer$propVal$(1) = multiCast     propVal$(2) = rtmp_enpropVal$(3) = rtmp_url$~errorKeywords$ = ""~errorKeywords$ =  chkRetStatusAndUpdate$(responseData$,propName$,propVal$)if len(~errorKeywords$) > 0 thenreturn -10elsereturn retendif       endif return ret          End Function

这样着,关键字添加完毕了,按照前面文章说的步骤编译生成吧..

boa端添加关键字的流程

只讲怎么添加。

请自行用工具定位下面变量,函数的位置。

先从SysInfo结构体开始修改,这个结构体将保存所有网页表单,关键字的值。

我们在末尾添加

typedef struct SysInfo{//....__u8 rtmp_enable; ///< rtmp_enablechar rtmp_url[MAX_RTMP_URL_LEN+1];
}SysInfo;

网页需要出厂默认值,所以在修改system_default.h文件添加两个宏定义。

#define RTMP_EANABLE_DEFAULT 0 //RTMP使能,0为不使能...
#define RTMP_URL_DEFAULT  "rtmp://192.168.1.120:1935/live/xxoo"

修改file_mng.c
修改全局静态结构体SysInfoDefault,往末尾添加

static SysInfo SysInfoDefault =
{//....RTMP_EANABLE_DEFAULT,RTMP_URL_DEFAULT
};

修改HttpOptionTable结构体。

HTTP_OPTION HttpOptionTable [] =
{//....{ "rtmp_en"         , set_rtmp_en               , AUTHORITY_OPERATOR, FALSE,  TRUE, NULL },{ "rtmp_url"                , set_rtmp_url                  , AUTHORITY_OPERATOR, FALSE,  TRUE, NULL },//...
}

接着在该表所在文件定义这两个函数,一个是整数,一个字符串,注意区别。

void set_rtmp_en(request *req, COMMAND_ARGUMENT *argm)
{__u8 value = atoi(argm->value);do {ControlSystemData(SFIELD_SET_RTMP_EN, (void *)&value, sizeof(value));req->buffer_end += sprintf(req_bufptr(req), OPTION_OK "%s\n", argm->name);return;} while (0);req->buffer_end += sprintf(req_bufptr(req), OPTION_NG "%s\n", argm->name);
}void set_rtmp_url(request *req, COMMAND_ARGUMENT *argm)
{do {if(ControlSystemData(SFIELD_SET_RTMP_URL, (void*)argm->value, strlen(argm->value)) < 0)break;req->buffer_end += sprintf(req_bufptr(req), OPTION_OK "%s\n", argm->name);return;} while (0);req->buffer_end += sprintf(req_bufptr(req), OPTION_NG "%s\n", argm->name);
}

sysctrl.h定义SFIELD_SET_RTMP_EN和SFIELD_SET_RTMP_URL

ControlSystemData函数中添加

        case SFIELD_SET_RTMP_URL:ret = SetSysCommon(data, len,SYS_MSG_SET_RTMP_URL);break;case SFIELD_SET_RTMP_EN:ret = SetSysCommon(data, len, SYS_MSG_SET_RTMP_EN);break;

Msg_Def.h中定义SYS_MSG_SET_RTMP_URLSYS_MSG_SET_RTMP_EN

ProcSysMsg函数添加

        case SYS_MSG_SET_RTMP_EN:{unsigned char value;DBG("SYS_MSG_SET_RTMP_EN\n");if(pMsg->length != sizeof(value))break;ShareMemRead(pMsg->offset, &value, pMsg->length);if(SetRtmpEn(value) != 0){printf("\nSystemServer:Fail at SYS_MSG_SET_MULTICAST\n");break;}ret = 1;break;}case SYS_MSG_SET_RTMP_URL:{if(pMsg->length > SYSTEM_SERVER_BUFFER_LENGTH){printf("String length bigger then System Server Buffer\n");break;}ShareMemRead(pMsg->offset, buffer, pMsg->length);if(SetRtmpUrl(buffer, pMsg->length) != 0){printf("Fail at SYS_MSG_SET_RTMP_URL\n");break;}ret = 1;break;}

定义SetRtmpUrlSetRtmpEn函数(这里在system_control.c中定义)

这两个函数的内容就非常自由了,不过和其它相同的地方就是就是需要将关键字保存到sysenv.cfg文件中。

所以分别各自定义一个函数用于保存关键字。

fSetRtmpEnfSetRtmpUrl(file_msg_drv.c)中定义。

int fSetRtmpEn(unsigned char value)
{SysInfo *pSysInfo = (SysInfo *)pShareMem;if(pSysInfo == NULL)return -1;if (value == pSysInfo->rtmp_enable)return 0;memcpy(&pSysInfo->rtmp_enable, &value, sizeof(value));return SetSysInfo(0);
}
int fSetRtmpUrl(void *buf, int len)
{SysInfo *pSysInfo = (SysInfo *)pShareMem;if(pSysInfo == NULL)return -1;if(sizeof(pSysInfo->rtmp_url) < len + 1)return -1;memcpy(&pSysInfo->rtmp_url, (char*)buf, len);pSysInfo->rtmp_url[len] = '\0';return SetSysInfo(0);
}

int SetRtmpEn(unsigned char value)
{int ret = 0;SysInfo *pSysInfo = GetSysInfo();if(pSysInfo == NULL)return -1;if(value != pSysInfo->rtmp_enable){ret = fSetRtmpEn(value);if ( value == 1 )rtmp_start();elsertmp_stop();}return ret;
}

int SetRtmpUrl(void * buf, int length)
{int ret = 0;signed char* serverip=(signed char*)buf;SysInfo *pSysInfo = GetSysInfo();if(pSysInfo == NULL)return -1;if(strncmp(serverip,pSysInfo->rtmp_url,length) != 0){ret = fSetRtmpUrl(buf,length);rtmp_stop();if ( pSysInfo->rtmp_enable )rtmp_start();}return ret;
}

修改HttpArgument结构体,用于获取关键字的值

HTML_ARGUMENT HttpArgument [] =
{//...{ "rtmp_en"     , para_rtmp_en              , AUTHORITY_VIEWER , NULL },{ "rtmp_url"            ,   para_rtmp_url       , AUTHORITY_VIEWER , NULL },//...
};

int para_rtmp_en(char *data, char *arg)
{SysInfo* pSysInfo = GetSysInfo();if(pSysInfo == NULL)return -1;return sprintf(data, "%d", pSysInfo->rtmp_enable);
}int para_rtmp_url(char *data, char *arg)
{SysInfo* pSysInfo = GetSysInfo();if(pSysInfo == NULL)return -1;return sprintf(data, "%s", pSysInfo->rtmp_url);
}

以上就成功的加入了关键字了,在其它线程里面,你只需要调用

    SysInfo *pSysInfo = GetSysInfo();//pSysInfo->rtmp_en//pSysInfo->rtmp_url

转载于:https://www.cnblogs.com/tracyone/p/4431698.html

相关文章:

Spring Cloud构建分布式电子商务平台:服务消费(基础)

使用LoadBalancerClient在Spring Cloud Commons中提供了大量的与服务治理相关的抽象接口&#xff0c;包括DiscoveryClient、这里我们即将介绍的LoadBalancerClient等。对于这些接口的定义我们在上一篇介绍服务注册与发现时已经说过&#xff0c;Spring Cloud做这一层抽象&#x…

OPENGL ES 对象的拾取

时间&#xff1a;19:51 2010-12-14 用户问题的说明 响应鼠标操作&#xff0c;其当中有一个非常重要的知识&#xff1a;使用鼠标点取&#xff0c;达到对三维模型对象的捕捉。 对象的拾取&#xff0c;这是3D当中的一个专业术语。也就是在二维屏幕当中选择三维对象。 我们要使用之…

如何禁止NumPy自动跳过数组的中心部分并仅打印角点

import numpy as np import sys np.set_printoptions(thresholdsys.maxsize)

用C#创建Windows服务(Windows Services)

转载自 hyslove最终编辑 hysloveWindows服务在Visual Studio 以前的版本中叫NT服务&#xff0c;在VS.net启用了新的名称。用Visual C# 创建Windows服务不是一件困难的事&#xff0c;本文就将指导你一步一步创建一个Windows服务并使用它。这个服务在启动和停止时&#xff0c;向一…

JS判断滚动条到底部

form:http://www.uphtm.com/js/269.html判断滚动条到底部&#xff0c;需要用到DOM的三个属性值&#xff0c;即scrollTop、clientHeight、scrollHeight。 scrollTop为滚动条在Y轴上的滚动距离。 clientHeight为内容可视区域的高度。 scrollHeight为内容可视区域的高度加上溢出…

docker容器网络 - 同一个host下的容器间通信

2019独角兽企业重金招聘Python工程师标准>>> 对于复杂的应用&#xff0c;不可避免需要多个服务部署在多个容器中&#xff0c;并且服务间存在相互间通信的情况。比如服务A需要连接mysql的容器。本文将介绍docker的容器网络&#xff0c;并通过实践解决在同一个docker …

登高自卑 | 我的PyTorch入门与实践笔记

1 函数名后带下划线会修改函数本身。如y.add_(x)会改变张量y。 2 PyTorch的Tensor和NumPy中的ndarray是可以互相转换的&#xff0c;转换后的对象共享内存(一个变另一个也跟着变)。

234. Palindrome Linked List - Easy

Given a singly linked list, determine if it is a palindrome. Example 1: Input: 1->2 Output: false Example 2: Input: 1->2->2->1 Output: true Follow up:Could you do it in O(n) time and O(1) space? 找中点&#xff0c;反转后半部分&#xff0c;再一一…

Hibernate 获取某个表全部记录时 奇怪现象 (重复出现某个记录)

我用Hibernate连接access的mdb 列出某个表全部记录的时候&#xff0c;发现有一个记录重复了。而直接用jdbc连接&#xff0c;就可以正确列出来。 本来还以为mdb不稳定&#xff0c;还吓了我一跳。毕竟打算用它作为长久数据库嘛~~ 分析了一下&#xff0c;发现正好重复的数据的主键…

iOS7导航栏和状态栏的定制

http://www.cocoachina.com/applenews/devnews/2013/1104/7287.html 转载于:https://www.cnblogs.com/luningning0901/p/4437190.html

2021年浙软夏令营预推免面经

夏令营 时间&#xff1a;七月中旬 参加人工智能分营&#xff0c;为期两周&#xff0c;评分标准&#xff1a;简历上课参与情况项目完成情况(具体占比不明)。 项目是完成三个深度学习模型&#xff0c;系统根据测试用例的通过情况评分。 预推免 时间&#xff1a;九月下旬 评…

ext前后台数据传输的标准化

一、标准化的数据传输是什么 这里所说的标准化主要是指&#xff0c;使用代理提交数据时&#xff0c;格式必须统一化、标准化&#xff0c;而服务器返回的数据格式也必须是标准化的数据。 简言之&#xff0c;使用代理提交数据时&#xff0c;前台--->后台&#xff0c;后台---&g…

对称加密解密类c#

namespace EncryptDLL{ #region 对称加密类 /// <summary> /// 对称加密解密类 /// </summary> public static class SymmetricEncryptClass { #region 对称加密代码 /// <summary> /// 对称加密方法 /// <…

java代码完全手写模仿qq登录界面

这是我模仿QQ2015版界面&#xff0c;实现的基本功能有登陆验证&#xff0c;重置等&#xff0c;当然直接复制代码运行是不一样的&#xff0c;还要注意自己插入自己的图片。 结果截图如下所示&#xff1a; import java.awt.BorderLayout;import java.awt.Color;import java.awt.F…

Vue3 计算属性的特性

computed:里面的方法 仅当依赖的值发生变动时&#xff0c;才会重新进行计算 这样一来解决的是性能问题 而methods里面的方法&#xff0c;哪怕无关值发生变动&#xff0c;也会重新进行计算 下面是两组对比 1-通过distance()计算属性来计算路程 2-通过getDis()方法计算路程…

解读源码中的问题

1.HashMap 构建中如何保证容量为 2 的幂次方 static final int tableSizeFor(int cap) {int n cap - 1;n | n >>> 1;n | n >>> 2;n | n >>> 4;n | n >>> 8;n | n >>> 16;return (n < 0) ? 1 : (n > MAXIMUM_CAPACITY) ?…

User Profile Data Web Part 读取属性字段

User Profile Data Web Part Property NameDisplay NameUserProfile_GUIDIdSIDSIDADGuidActive Directory IDAccountName帐户名FirstName名字SPS-PhoneticFirstName拼音名LastName姓氏SPS-PhoneticLastName拼音姓PreferredName名称SPS-PhoneticDisplayName拼音显示姓名WorkPho…

Linux 环境变量配置

linux 环境&#xff0c;用户通过shell 操作时&#xff0c;系统会为用户初使化环境变量&#xff0c; 比如系统公共资源路径: path , include , bin 等目录。 shell 模式下&#xff0c;执行 export &#xff0c; 查看用户环境变量 , echo $key 查询某个环境变量。设置环境变量&am…

Android 自定义View之3D骰子旋转

你可以指定立方体中每一面骰子的点数&#xff0c;颜色和背景&#xff0c;同时也可以指定执行的动画时间和动画插值器 更多有趣的view 使用 在根目录的build.gradle添加这一句代码&#xff1a; allprojects {repositories {//...maven { url https://jitpack.io }} } 复制代码在…

职业生涯的考虑

职业核心价值&#xff1a;活的有价值&#xff0c;有意义 第一阶段&#xff1a;技术&#xff08;27:2012&#xff5e;30:2015&#xff09;&#xff1a;移动互联网 第二阶段&#xff1a;销售或者管理&#xff08;30:2015&#xff5e;35:2020&#xff09;&#xff1a;成熟公司 第三…

算法的sound和complete

stackoverflow的答案 Soundness and Completeness of a algorithm stackexchange的答案 What does it mean to say an algorithm is Sound and Complete?

ArcGIS API for Silverlight 入门学习笔记(三):基础地图实例

该实例主要是包含六部分&#xff1a;地图范围、坐标、动画效果、全屏、比例尺、进度条。 前期准备工作 前台代码0 <UserControl x:Class"APIforSilverlightSamp.s2" xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x"ht…

BZOJ 4009 接水果

Description 风见幽香非常喜欢玩一个叫做osu!的游戏&#xff0c;其中她最喜欢玩的模式就是接水果。 由于她已经DT FC了The big black, 她觉得这个游戏太简单了&#xff0c;于是发明了一个更加难的版本。首先有一个地图&#xff0c;是一棵由\(n\)个顶点、\(n-1\)条边组成的树。这…

GitBook本地的安装与查看

1.安装nodejs 2.cnpm install -g gitbook-cli 查看版本&#xff1a;gitbook -V 3.gitbook init 注意npm加了代理&#xff0c;查看npm代理配置&#xff0c;将其注释即可 执行完后&#xff0c;你会看到多了两个文件 —— README.md 和 SUMMARY.md&#xff0c;它们的作用如下&…

用C++的random_shuffle()函数打乱int数组顺序

程序背景&#xff1a; 开组会&#xff0c;汇报人已确定&#xff0c;出一个随机的汇报顺序。 #include<bits/stdc.h> using namespace std;const int NUM 12;//汇报人数 int main() {string names[] {"SpongeBob","Patrick","Squidward"…

ios 绘制不规则 图形

最近才知道有一个软件 paintcode 它可以根据画出的图形自动的生成对应的 OC 代码 不用UI切图 我们也可以用代码实现自己想要的图形效果 使用教程可以百度&#xff1a;paintcode教程 http://blog.csdn.net/lujunelong/article/details/18899925 下载地址&#xff1a;http://www…

[转]Windows与VC命名规则

转自&#xff1a;http://hi.baidu.com/11158512/blog/item/0fbd5535cbfb5d1c91ef3970.html 匈牙利命名法是一种编程时的命名规范。基本原则是&#xff1a;变量名&#xff1d;属性&#xff0b;类型&#xff0b;对象描述。其中每一对象的名称都要求有明确含义&#xff0c;可以取对…

恢复误删的进程在使用的文件【转】

转自&#xff1a;https://www.cnblogs.com/276815076/p/5473185.html 原理&#xff1a;在Linux系统的/proc 分区下保存着进程的目录和名字&#xff0c;包含fd(文件描述符)和其下的子目录&#xff08;进程打开文件的链接&#xff09;&#xff0c;那么如果删除了一个文件&#xf…

编解码器架构中的桥(bridge)指什么

https://opennmt.net/OpenNMT-py/examples/Summarization.html?highlightbridge​​​​​​对于bridge做出如下解释 bridge: This is an additional layer that uses the final hidden state of the encoder as input and computes an initial hidden state for the decoder.…