AAUTO是一个国产小众语言,和lua算是近亲,官方网站 www.aau.cn。
使用aauto的优点我认为对于我来说最主要的有以下两点:
1.无需臃肿的框架类似.NET FRAMEWORK、Adobe AIR等便可开发出小巧而实用的windows程序
2.支持HTMLLAYOUT,对于原来熟悉html+css的web开发者来说是个福音,降低了学习成本
废话不多说了,下面开始介绍下我使用aauto这个短小精悍的语言所开发的访问使用CloudStack所创建的虚拟机的云桌面访问客户端。
界面演示
实现功能
该客户端在输入用户名密码验证登录成功后
1.屏蔽了windows,ALT+F4 以禁止用户返回原生桌面或关闭当前程序(其实屏蔽ALT+F4)
架构详解
下图是该项目的全部文件目录树。
该客户端仅有一个主窗体文件main.aau,界面演示图中的效果是有layout中的index.html实现。sys.ini中配置保存的用户名及登录验证服务网址.
代码详解
main.aau中核心代码如下:
import win.ui;
import win.ui.menu;
import win.ui.atom;
import win.timer;
import inet.whttp;
import web.layout;
import web.layout.behavior.windowCommand;
import fsys.ini;
import sys;
import win.reg;
import key;
import crypt.des;
import crypt.bin;
_ver = "1.1.0 build 20141017"
//常量定义
_APP_NAME="clouddesktop"
mainForm = win.form(text="云桌面登录客户端";right=0;bottom=0;border="none";max=false;min=false;maxmize=1)
var debug =(_STUDIO_INVOKED ? true:false)
var des = crypt.des();
des.setPassword("huiyou");
if(!debug){
win.setTopmost(mainForm.hwnd)
}
/*------------------ 公用函数 -------------------*/
function decrypt(str){
var rtn = crypt.bin.decodeBase64(str);
return des.decrypt(rtn);
}
function encrypt(str) {
var rtn = des.encrypt(str);
return crypt.bin.encodeBase64(rtn);
}
/*------------------ 公用函数 END -------------------*/
//win.setTopmost(mainForm.hwnd)
var atom,hwnd/*冲突窗口的句柄,该函数会自动激活此窗口*/ = mainForm.atom("BB84EAAE-004C-4AF7-8087-98550285C32E");
if(!atom){
/*为窗口设置原子值可以避免一个程序重复运行多个实例*/
win.quitMessage();
return;
}
var ini = fsys.ini("/sys.ini")
//1.禁用任务管理器
var reg = win.reg("HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionPoliciesSystem")
reg.setDwValue("DisableTaskMgr",1)
var binpath = io._exepath;
var displayname = "云桌面客户端"
var description = "云桌面客户端"
/*自动启动*/
reg = win.reg("HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionRun")
reg.setSzValue(_APP_NAME, binpath)
//reg.delKeyTree("HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionRunclouddesktop")
//禁用运行
reg = win.reg("HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionPoliciesExplorer")
reg.setDwValue("DisallowRun",1)
wbLayout = web.layout(mainForm)
//禁止窗体绘制默认背景,避免不必要的闪烁
mainForm.onEraseBkgnd = function(hwnd,message,wParam,lParam){
return 0;
}
wbLayout.go("/layout/index.html");
//----------------屏蔽按键
import key.hook;
hk = key.hook()
hk.proc = function(msg,vkcode,scancode,injected,flags,timeStamp,extraInfo){
if( injected ) return;
var kn = key.getName( vkcode );
select(msg) {
case 0x100/*_WM_KEYDOWN*/ ,0x104/*_WM_SYSKEYDOWN*/{
if(kn=="LWIN" || kn=="RWIN"
|| ((flags & 0x20/*_LLKHF_ALTDOWN*/)!=0 && kn=="F4")
)
{
return true
}
elseif( kn == "0" && key.getStateX("CTRL")){
reg.close();win.quitMessage();
}
}
}
}
//----------------屏蔽按键END
timer=win.timer( mainForm);
quit = function(){hk.close();timer.disable();reg.close();win.quitMessage();}
_section_AutoLogin="autologin"
var isAutoLogin=false;
if(ini.readKeys(_section_AutoLogin)){
sec = ini.getSection(_section_AutoLogin)
rememberUserName=sec.rememberUserName//记住用户名
//autoLogin=sec.autoLogin
}
if(rememberUserName=="1"){
wbLayout.getEle("cbxRemember").value=true
wbLayout.getEle("username").value= decrypt(sec.userName)
}
/*
if(autoLogin=="1"){
isAutoLogin=true;
wbLayout.getEle("userpass").value = sec.userPass;
wbLayout.getEle("cbxAutoLogin").value = true
wbLayout.getEle("btnSmt").click()
}
*/
var http = inet.whttp();
//请求服务baseurl,可用用户名
var serverBaseUrl=ini.read("server","url","http://140.28.22.122:8080/admin/getvm");
if(false == string.startWith(serverBaseUrl,"http://")){
serverBaseUrl = decrypt(serverBaseUrl);
}
wbLayout.onButtonClick = function (ltTarget,ltEle,reason,behaviorParams) {
if( ltEle.id == "btnSmt"){
var username=wbLayout.getEle("username").value;
var password=wbLayout.getEle("password").value;
rememberUserName=wbLayout.getEle("cbxRemember").value;
//autoLogin=wbLayout.getEle("cbxAutoLogin").value;
if(username=="用户名")username="t1"
if(!#password || password=="密码")password="t1"
if(!#username){mainForm.msgbox("请输入用户名")return;}
if(!#password){mainForm.msgbox("请输入密码")return;}
var url=string.concat(serverBaseUrl,"?command=getsvm&username=",username,"&password=",password);
var str;
try{str = http.get(url)}
catch(e){mainForm.msgbox("无法连接到远程服务,请检查远程服务是否可访问");return;}
if( null ==str || !#str){mainForm.msgbox("登录失败,请检查网络连接情况并稍后再试");return}
if(str=="1"){mainForm.msgbox("登录失败,请检查用户名密码是否正确");return}
//------------ 保存用户名密码等到配置文件
/*保存用户名密码等到配置文件{{*/
ini.write(_section_AutoLogin,"rememberUserName",rememberUserName?1:0)
//ini.write(_section_AutoLogin,"autoLogin",autoLogin?1:0)
if(rememberUserName){
var sUserName = des.encrypt(username);
ini.write(_section_AutoLogin,"userName",crypt.bin.encodeBase64(sUserName));
}
/*
if(autoLogin){
ini.write(_section_AutoLogin,"userPass",password)
}
*/
/*}}*/
//------------ 保存用户名密码等到配置文件 END
if(isAutoLogin){
ltEle.value="登陆中...";
}
var arr= string.split(str,'$')
userid=arr[1];
var serverip=arr[2];
var port = arr[3];
var vmUserName=arr[4];
var vmpwd = arr[5];
var desktopUrl=arr[6];
//-------------- 远程连接start
import com.lite;
rdpClient = com.lite("MsTscAx.dll").createEmbed(mainForm,"{7cacbd7b-0d99-468f-ac33-22e495c0afe5}")
msTscAx = rdpClient._object;//获取控件对象
//响应远程桌面事件
rdpClient.OnDisconnected = function(discReason){
//mainForm.msgbox(discReason)
select (discReason) {
case 1,2{
quit();
if(!debug)sys.shutdown();
}
}
}
//设置远程登录参数
msTscAx.Server = serverip;
msTscAx.UserName = vmUserName;
msTscAx.AdvancedSettings2.ClearTextPassword = vmpwd;
msTscAx.AdvancedSettings2.RDPPort = port; //端口
msTscAx.AdvancedSettings2.RedirectPrinters = true; //共享打印
msTscAx.AdvancedSettings2.RedirectDrives = true; //允许共享磁盘
msTscAx.AdvancedSettings2.RedirectDynamicDrives =true;
msTscAx.AdvancedSettings2.SmartSizing = true; //自动调整大小
msTscAx.AdvancedSettings2.DisplayConnectionBar=true;
msTscAx.AdvancedSettings2.DisableCtrlAltDel = 1;
msTscAx.AdvancedSettings2.EnableWindowsKey = 0;
//msTscAx.AdvancedSettings.Compress=1;
//msTscAx.AdvancedSettings.BitmapPeristence = 1;// 将位图缓存到磁盘
//msTscAx.SecuredSettings2.StartProgram = "c:rowser.exe "++ desktopUrl;
msTscAx.FullScreen = false;//是否全
msTscAx.FullScreenTitle = mainForm.text;//全屏标题
msTscAx.ColorDepth = 32;//32位颜色
msTscAx.ConnectingText = "欢迎使用云桌面,正在连接,请稍候......"
msTscAx.Connect(); //连接
//-------------- 远程连接 END
//加载计时器
timer.enable();
timer.setInterval(120000)//2分钟发送一次heartbeat
}
}
var elePwd = wbLayout.getEle("userpass")
elePwd.onKeyUp = function( ltTarget,ltOwner,keyCode, altState, ltKeyParams ) {
if(ltOwner.id == "userpass" && keyCode==13){wbLayout.getEle("btnSmt").click()}
}
elePwd.attachEventHandler()
//发送heartbeat
timer.onTimer = function(hwnd,msg,id,tick){
if(!userid || !#userid) return;
var url=string.concat(serverBaseUrl,"?command=heartbeat&userid=",userid);
http.get(url);
}
mainForm.onClose = function(hwnd,message,wParam,lParam){
return false;
if(#userid){
var url=string.concat(serverBaseUrl,"?command=logout&userid=",userid);
http.get(url);
http.close()
}
process.kill("mstsc.exe")
quit();
collectgarbage("collect");//内存回收,确保完全退出
if(!debug)sys.shutdown();
}
//响应窗口事件
mainForm.wndproc = function(hwnd, message,wparam,lparam){
select(message) {//判断消息类型
case 0x10/*_WM_CLOSE*/{
return true;//阻止关闭
};
case 0x282
{
import winex;
var winHwnd,ch,tid,pid = winex.findExists("<云桌面登录客户端>","","<AAU_FORM[S+]>","<ATL:w+>")
if(ch!=null){
rdpClient._host.doObjectVerb( -5)
}
};
}
}//endproc
mainForm.show()
//import cloudDesktop.common;
//cloudDesktop.common.checkUpdate();
win.loopMessage();
sys.ini中内容
[autologin]
userName=7JB75wW03kA=
rememberUserName=1
[server]
url=http://xxxxxx/admin/getvm