//command 进程命令 import win.ui; import thread.table; namespace ide; class command{ ctor( winform,changeMsgFilter ){ if(!winform){ winform = ..win.form( {} ); winform.messageOnly(); } this._form = winform; this._commands = {}; if( winform.onCopyData ){ error("目标窗口已指定onCopyData事件,不能创建进程命令管理器!",2) } if( changeMsgFilter && ChangeWindowMessageFilterEx ){ ChangeWindowMessageFilterEx( this._form.hwnd,0x4A/*_WM_COPYDATA*/,1/*_MSGFLT_ALLOW*/,{}); } winform.onCopyData = function(args){ if( type(args) !="table" ) return; var method = this._commands[args[1] ] if(type(method)=="function"){ var _,argc = ..table.range(args) var ret = invoke(method,this._commands, ..table.unpack( args,2,argc) ); if( ret !== null ) return pushReturnValue(ret); } } ..table.gc(this,function(){ for(name in this._commands ){ this[name] = null; } }); }; @_meta; } import process.mutex; import fsys.mmap; namespace command { try{ ChangeWindowMessageFilterEx = ::User32.api( "ChangeWindowMessageFilterEx", "bool(addr hwnd,INT msg,INT flag,struct &chgFilter)"); } var mutex,mmap,__groupName__; var joinTest = function(name,size){ if(!#name) name = "{B5B96695-F51A-4FCC-813E-9FA9A7A55500}"; if( __groupName__ ) { if( __groupName__ != name ) error("该线程已加入其他进程群组:" + __groupName__ + "\n不能再加入群组:" + name,2); else{ return true;} } mutex = ..process.mutex( name + ".mutex"); mmap = ..fsys.mmap( ,name + ".commands",size); if(mutex && mmap){ __groupName__ = name; return true; } } joined = lambda() !!__groupName__; join = function(name,size=0x100000){ for(i=1;5;1){ if( joinTest(name,size) ){ return true; } sleep(200); } var dbg = { mutex = !!mutex; mmap = !!mmap; __groupName__ = __groupName__; name = name; } var err = ..lasterr(); error( ..string.concat("注册进程群组时遇到错误" ,'\r\n',err," ->",..table.tostring(dbg)),2); } each = function(){ var aardioWindows = {} for hwnd in ..win.eachChild(,"Afx\:[\x\:]+") { if(..win.findEx(hwnd,,"MDIClient")){ var tid,pid = ..win.getThreadProcessId( hwnd ); var gId = ..string.concat( "{5D345FB2-C8CC-4EA6-B762-FCB2A40CE799}.aardio.ide[" + pid + "]"); var mutex = ..process.mutex(gId + ".mutex"); if(mutex){ if(mutex.conflict){ ..table.push(aardioWindows,{ hwnd = hwnd; gId = gId; }) } mutex.close() } } } var i,v; return function(){ i,v = ..table.next(aardioWindows,i); if(v){ return v.hwnd,v.gId } } } pushReturnValue = function(v){ if(! mutex.waitOne() ) return; mmap.seek("set"); var commandTable = mmap.readTable() : {}; if(!commandTable[-1])commandTable[-1] = {}; var ret = ..table.push(commandTable[-1],v); mmap.seek("set"); mmap.writeTable(commandTable); mutex.release(); return ret; } getReturnValue = function(idx){ if(! mutex.waitOne() ) return; mmap.seek("set"); var commandTable = mmap.readTable() : {}; var ret; if(commandTable[-1]){ ret = commandTable[-1][idx] ? ..table.remove(commandTable[-1],idx); mmap.seek("set"); mmap.writeTable(commandTable); } else mmap.seek("set"); mutex.release(); return ret; } _meta = { _set = function(k,v){ if(!mutex) error("进程必须调用 ide.command.join() 函数初始化",2); if( k == -1 ) error("命令名不能设置为保留值-1",2); if(! mutex.waitOne() ) return; mmap.seek("set"); var commandTable = mmap.readTable() : {}; if(!commandTable[k])commandTable[k] = {}; commandTable[k][owner._form.hwnd] = v?true:null; mmap.seek("set"); mmap.writeTable(commandTable); owner._commands[k] = v; mutex.release(); } }; sendPid = function(pidDst,method,...){ var subscribe; if(! mutex.waitOne() ) return; mmap.seek("set"); subscribe = mmap.readTable()[[realName]]; mmap.seek("set"); mutex.release(); var ret,tid,pid; var sendTable = {method;...}; for(hwnd in subscribe){ tid,pid = ..win.getThreadProcessId(); if(pid!=pidDst) continue; ret = ..win.sendCopyData( hwnd,sendTable ); if( ret ) return getReturnValue( ret ); } return; } send = function(hwnd,method,... ){ if(!mutex) error("进程必须调用 ide.command.join() 函数初始化",2); var t = type(hwnd); if( t == "string" ){ var realName = hwnd; var sendTable = {realName;method;...}; var subscribe; if(! mutex.waitOne() ) return; mmap.seek("set"); subscribe = mmap.readTable()[[realName]]; mmap.seek("set"); mutex.release(); var ret; for(hwnd in subscribe){ ret = ..win.sendCopyData( hwnd,sendTable ); if( ret ) return getReturnValue( ret ); } return; } elseif(t == "number" ){ var sendTable = {method;...}; var ret = ..win.sendCopyData( hwnd,sendTable ) if( ret ) return getReturnValue( ret ); }; }; post = function( ... ){ ..thread.invoke( function(__groupName__,... ){ import ide.command; ide.command.join(__groupName__) ide.command.send( ... ); },__groupName__,... ) }; self.invoke = function(...){ return ..thread.invokeAndWait( function(__groupName__,... ){ import ide.command; ide.command.join(__groupName__) return ide.command.send( ... ); },__groupName__,... ) } self@ = { _get = function(k){ self[[k]] = function(...){ return owner.send(k,...); } return self[[k]]; } } } /**intellisense() ide.command = 只允许在 ide 扩展库、以及IDE启动触发器 init.aardio 中使用。\n用于避免在 IDE 中因为导入ide接口而无法支持 process.command ide.command.joined() = 进程是否已加入进程命令群组。 ide.command.join(.("群组ID") = 加入进程命令群组。\n使用群组 ID 区分不同的进程命令分组。\n同一线程应当且必须在定义或发送进程命令前调用该函数一次,\n同一线程可多次调用该函数,但参数必须相同。\n成功返回true。\n试图加入不同的群组会抛出异常。\nide.command 不能与 process.command 使用相同的群组 ID。 ide.command.sendPid(.(目标进程ID,"命令函数名",其他参数) = 阻塞调用跨进程命令,\n可获取回调函数的数值返回值,默认返回null ide.command.post(.("命令函数名",其他参数) = 非阻塞调用跨进程命令,无返回值\n此函数需要创建线程调用send函数,不适合频繁调用\n异步命令如果尚未发出前,发送线程如果立即退出会导到命令发送失败 ide.command.invoke(.("命令函数名",其他参数) = 非阻塞调用跨进程命令,支持返回值 ide.command.send(.(窗口句柄,"命令函数名",其他参数) = 阻塞调用跨进程命令,\n可获取回调函数的数值返回值,默认返回null ide.command.send(.("命令函数名",其他参数) = 阻塞调用跨进程命令\n不指定窗口句柄,所有同名的进程命令函数都会被调用,\n可获取处理该命令的回调函数返回值,默认返回0 ide.command.? = 可指定外部进程的命令函数名,并直接调用该函数,\n可获取外部进程中被调用函数的返回值 ide.command(.(窗口对象,是否取消特权隔离) = 创建进程命令对象\n省略窗口参数则创建 message only window,\n该对象定义的成员函数,都可在其他进程中用 thread.command.post()调用 ide.command() = !ide_command. !ide_command.自定义函数名 = @.命令函数 = function( ... ) { __/*支持不定个数参数\n返回值可阻止命令继续传递*/ } !ide_command._form = 窗体对象\n!winform. ide.command.each() = @for hwnd,groupId in ide.command.each(){ __/*遍历 aardio 开发环境主窗口。\nhwnd 为主窗口句柄,groupId 为 ide.command 进程群组 ID。*/ } end intellisense**/