//.. 编译前预处理 
namespace preload {}  

::User32 = ::MSG;
::User32 = raw.loadDll("User32.dll");
::Kernel32 = raw.loadDll("Kernel32.dll");
::GetModuleHandle = Kernel32.api( "GetModuleHandleA", "pointer(string)");

::FILETIME = class { 
	INT dwLowDateTime ;
	INT dwHighDateTime ;
}

//内存 API
::GlobalAlloc = Kernel32.api("GlobalAlloc","ptr(INT,INT)" ) ;
::GlobalLock = Kernel32.api("GlobalLock","ptr(ptr)" ) ;
::GlobalUnlock = Kernel32.api("GlobalUnlock","bool(ptr)" ) 
::GlobalFree = Kernel32.api("GlobalFree","ptr(ptr)" )

/**intellisense(::)
::User32=@User32.api( "__/*函数名字*/", "int()"); 
::Kernel32=@Kernel32.api( "__/*函数名字*/", "int()"); 
::FILETIME() = 该结构的64位值,\n表示从1601年1月1日开始的以100纳秒为间隔的值
::GetModuleHandle(__/*模块名*/) = 返回动态链接库的模块句柄 
::GlobalAlloc(0,__/*长度*/) = 在进程堆上分配内存\n如果参数一为0,则直接返回指针
::GlobalAlloc(2,__/*长度*/) = 在进程堆上分配可移动内存\n如果参数一为2,则直接返回句柄,\n句柄可使用 GlobalLock() 转换为内存指针.
::GlobalLock(__/*内存句柄*/) = 锁定::GlobalAlloc(0x2/*_GMEM_MOVEABLE*/)创建的内存句柄,\n并返回内存指针指针
::GlobalUnlock(__/*内存句柄*/) = 解锁::GlobalAlloc(0x2/*_GMEM_MOVEABLE*/)创建的内存句柄,\n成功返回true
::GlobalFree(__/*内存句柄*/) = 释放::GlobalAlloc()分配的内存\n如果成功返回null,否则返回传入句柄
::GetLastError() = 返回系统错误代码
end intellisense**/

_HINSTANSE = ::GetModuleHandle();
_INVALID_HANDLE_VALUE = topointer(-1);
gcdata = function(t){
	var d = ..raw.malloc(1);d@ = t;
	return d;
}; 
/**intellisense()
_INVALID_HANDLE_VALUE = topointer(-1)\n表示无效句柄 
FILETIME() = FILETIME结构
_HINSTANSE = 当前应用程序的实例句柄;
gcdata(元表) = @..gcdata(  \n	_topointer =  __/*pointer指针*/ \n	_gc = function(){\n		\n	} \n)
end intellisense**/

namespace string{ 
	fromto = function(s,cp=65001,tcp=0) {
		if( (!#s) || (cp==tcp) ){ return s; };
		s = toUnicode(s,cp ); 
		return fromUnicode(s,tcp); 
	};
	gSearch = function(s,p){
		var i,j  = 0,0;
		return function(){ 
			i,j = search(s,p,j+1); 
			return i,j
		};
	};
	lastSearch = function(s,p){
		var a,b;
		for i,j in gSearch(s,p){
			a,b = i,j;
		};
		return a,b;
	};
	cmp_match = function(a,b){
		return  ( type(a)==type(b) && ( ( cmp( a,b) == 0 ) ||  ( match( a  ,b ) ) ) )  
	};
}

/**intellisense()
string.fromto(.(字符串,源编码,目标编码) = 源编码为可选参数,默认为65001(UTF8)\n目标编码默认为0 
string.lastSearch(.(字符串,查找文本) = 在字符串尾部查找匹配文本\n不支持模式语法,较好支持宽字符
string.gSearch(字符串,查找文本) = @for i,j in string.gSearch(str,"__/*查找文本*/"){
	
}
string.cmp_match( __,"" ) = 忽略大小写比较两个字符串\n如果失败则使用模式语法匹配是否相同.\n如果其中一个参数不是字符串则返回false
end intellisense**/

namespace table{ 

	splice = function(t,p=1,l,...){ 
		var ret;
		if(p<0) 
			p=#t+p+1
		if(!p || p > #t)
			error("Index out of range",2);
		if( l>0 ) {
			ret = slice(t,p,p+l-1); 
			var max = #t;
			for(i=p+l;max){
				t[i-l] = t[i];
			}
			for(i=max-l+1;max){
				t[i] = null;
			}
		} 
		
		p--;
		var a = {...}
		for(i=1;#a ) 
			insert(t,a[i],p+i)  
		return ret; 
	};	
	
	slice = function(t,i=1,j){   
  		return {  ..table.unpack(t,i,j) };
	};
	
	mixin = function(a,b,...){
		for(k,v in b) if( (!a[[k]]) || (type(k)!="string") || (k[1]!='_'#) ) a[k] = v; 
		if(!...) return a;   
		return mixin(a,...); 
	};  
	mix = function(a,b,...){
		for(k,v in b) if( !a[[k]] ){ a[k] = v}; 
		if(!...) return a;   
		return mix(a,...);
	};
	delegate = function(o,...){
		return mixin({ @{_get = o } },...);
	};
	
	array = function(l,v,...){ 
		var r = {}
		var t = type(v);
		if( (... !== null) && ( t == "number") ) 
			for(i=1;l )  r[i]=array(v,...); 
		else { 
			if( t == "function" || t == "class" ) 
				for(i=1;l) r[i]= v(...);  
			elseif( t == "table" ) 
				for(i=1;l) r[i]= mixin({},v); 
			else {
				for(i=1;l) r[i]= v; 
			} 
		}
		return r;
	}; 
	
	getByNamespace = function(k,t){
		if(!t){ t = ..global; }
		var p,m = ..string.match(k,"\.*(.+)(%\[\])$");
		if( m )
			m = eval(..string.trim(m,"[]")); 
		else
			p,m = ..string.match(k,"\.*(.+)\.([^.]+)$");
		if( m!==null ){ t = getByNamespace(p,t); if(t){ return t[m],t; } }
		else{ return t[k],t };
	};
	
	var setByNamespace_;
	setByNamespace_ = function(k,v,t,n=0){  
		var p,m = ..string.match(k,"\.*(.+)(%\[\])$");
		if( m ){
			t = setByNamespace_(p,,t,n+1);
			k = eval(..string.trim(m,"[]"))
			if(k===null)k=#t+1;
		}
		else{
			p,m = ..string.match(k,"\.*(.+)\.([^.]+)$"); 
			if( m!==null ){ t = setByNamespace_(p,,t,n+1); k = m }
		}
		
		if( n ){
			if( t[k]===null ) t[k] = (v===null) ? {} : v ;
		}
		else{
			t[k] = v;
		} 
		return t[k];
	};
	setByNamespace = function(k,v,t){
		if(!t){ t = ..global }
		return setByNamespace_(k,v,t,0)
	};	
	
	count = function(t){
		var i = 0;
		for(k,v in t){i++};
		return i;
	}; 
	
	add_gc = function(o,gc ){
		var gd = ..raw.malloc(1);
		gd@ = { _gc = function(){ call( type(gc)=="string"?o[gc]:gc,o);} }
		o._gc = gd;
		return o;
	}; 
} 
/**intellisense(table)
array(.(任意个数组长度,默认值) = 可使用不定个数长度参数指定多维数组长度, 例：\n table.array(3,5,{} ); \n如果默认值是table对象，自动复制创建新值。
array(.(任意个数组长度,函数或类,任意个调用参数) = 可使用不定个数长度参数指定多维数组长度,\n最后一个参数可以是创建默认值的函数或类，并在后面指定调用参数。

count() = 返回table对象成员总数
splice(.(数组,位置,删除长度,要插入的一个或多个元素) = 直接修改传入数组\n如果删除了元素,该函数返回包含删除元素的数组
slice(.(数组,开始位置,结束位置) = 从指定位置截取并返回新数组\n开始位置可选，默认为1\n结束位置可选,默认为数组长度\n如果位置参数为负数,则自右侧反向计算
mixin(.(对象,任意多个混入对象) = 使用后面的对象混入前面的对象(浅拷贝),并返回该对象\n该函数仅修改第一个参数(混入目标) ,覆盖已存在的键值
mix(.(对象,任意多个混入对象) = 使用后面的对象补全前面的对象(浅拷贝),并返回该对象\n该函数仅修改第一个参数(混入目标),不覆盖已存在的键值.
delegate(.(委托对象,任意多个混入对象) = 创建一个委托对象的镜像副本,混入后续参数指定的其他对象.\n副本并不复制委托对象,委托对象的改动也会体现到副本中.\n但修改副本对象并不污染委托对象. 
delegate(.(委托元函数,任意多个混入对象) = 创建一个对象,混入后续参数指定的其他对象.\n并将委托函数作为新对象的 _get 元方法.
add_gc(.(table对象,函数对象)  = 添加键名为 "_gc" 的cdata析构对象,\n将参数二指定的函数设定为该对象的析构函数,\n并将参数一绑定为该析构函数的owner参数.\n注意析构函数不应抛出异常,否则可能导致未知程序错误.\n函数返回table对象自身
add_gc(.(table对象,"成员函数名") =  添加键名为 "_gc" 的cdata析构对象,\n将参数二指定的函数设定为该对象的析构函数,\n并将参数一绑定为该析构函数的owner参数.\n函数名可以是之后创建的成员函数.\n注意析构函数不应抛出异常,否则可能导致未知程序错误.\n函数返回table对象自身
add_gc( = 添加对象在销毁前执行的析构函数 
getByNamespace(.("表内名字空间路径->名字[2]",表对象) = 返回两个值:名字路径指向对象,该对象所在的表.\n参数一为表内名字空间路径,参数二可选指定查找路径的表对象,\n默认在global全局对象内查找路径.
setByNamespace(.("表内名字空间路径->名字[]",新值,表对象) = 参数一指定表内名字空间路径,如果不存在则则创建此表内名字空间,\n参数二指定需要设置的值,如果不指定则创建空表并赋值,\n参数三可选指定一个表对象,默认为global全局对象
end intellisense**/  

::GetLastError = ::Kernel32.api( "GetLastError", "int()"); 
var formatMessage = ::Kernel32.api("FormatMessageA","INT(INT dwFlags,pointer source,INT id,INT lang,str& buf,INT size,pointer &arg )");
lasterr  = function(err,where){
	err := GetLastError(); 
	if(err){ 
		var len,str =  formatMessage( 0x1000 /*_FORMAT_MESSAGE_FROM_SYSTEM*/,null, err,1024/*默认语言*/, 80, 80 );
		return ..string.concat(str,where),err;
	}
}; 

//线程库扩展模块;
::WaitForSingleObject := ::Kernel32.api("WaitForSingleObject", "INT(pointer hHandle,INT dwMilliseconds)");
::WaitForMultipleObjects := Kernel32.api("WaitForMultipleObjects", "INT(INT nCount,struct lpHandles,INT bWaitAll,INT dwMilliseconds)");
::MsgWaitForMultipleObjects := User32.api("MsgWaitForMultipleObjects", "INT(INT nCount,struct lpHandles,INT bWaitAll,INT dwMilliseconds,INT dwWakeMask)");
 
var threadwait = function( bClose,bAll, ...){
    var threads,timeout = ...;
    if(type(threads)!=type.table) {
    	timeout = 0xFFFFFFFF
    	threads ={...}
    	if( type(threads[#threads]) == type.number ){
    		timeout = ..table.pop(threads,1)
    	}
    }
    elseif(timeout === null )
    	timeout = 0xFFFFFFFF  /* Infinite timeout*/
    	
    var len = #threads
    if(!len) error("参数未指定线程句柄",3);
    var threads_c = raw.toarray( threads ,"pointer" ,"array");
    var waitfunc,msgDummy,peekPumpMessage; 
    
    if( (!bAll) && win[["form"]] ){
    	msgDummy = {};
		peekPumpMessage = win.peekPumpMessage;
    	waitfunc = MsgWaitForMultipleObjects;
    }
    else {
    	waitfunc = WaitForMultipleObjects
    }
  
	var re; 
	do{
		re = waitfunc(len,threads_c,bAll,timeout, 0x4FF/*_QS_ALLINPUT*/);
		if( re & 0x102 ){
	 		if( ( re == 0x102 ) && ( timeout != 0xFFFFFFFF) ) //WAIT_TIMEOUT 
				return null,"超时" 
			elseif( re == 0xFFFFFFFF )
				return null,"失败"   
		};  
	}while( re==len && ( peekPumpMessage(msgDummy)!== null ) ) 
	 
	if( re == len) {
		return null;
	}
	elseif( re & 0x80 ){
		return null,re+1;//mutex
	}
	else{
		if( bClose ){
			for(i,h in threads){
				..raw.closehandle(h);
			};
		}
		return re+1;
	}
}; 
 
thread.waitAll = function(...){
	return threadwait(false,1,...);
};

thread.waitClose = function(...){ 
	return threadwait(true,1,...);
};  

thread.waitOne = function(...){ 
	return threadwait(false,0,...);
};

thread.wait  = function(handle,ms=0xFFFFFFFF){
	return WaitForSingleObject(handle,ms)== 0/*_WAIT_OBJECT_0*/;
}; 
 
var SetThreadAffinityMask = Kernel32.api("SetThreadAffinityMask","INT(pointer thread,INT mask)" )
thread.setAffinity = function( cpu = 1,h){
	if(!h) h = thread.getHandle();
    SetThreadAffinityMask( h,cpu );
};

/*intellisense()
lasterr() = 返回WINAPI或COM API的最后一次错误信息,第二个返回值为错误码\n无错误则返回null空值
thread.setAffinity(2,__) = 指定线程在哪个CPU上运行\n参数一指定CPU
thread.setAffinity(1) = 指定线程在CPU 1上运行 
thread.waitOne(__) = 等待一个或多个线程其中一个返回\n参数可以是多个线程句柄,或包含多个线程句柄的table,\n可选使用最后一个参数指定超时值(毫秒)\n如果在主线程中调用此函数,在等待过程中可处理窗口消息\n注意线程句柄不能大于64个
thread.wait(__) =  等待一个线程句柄返回\n可选使用第二个参数指定超时值(毫秒)
thread.waitAll(__) = 等待一个或多个线程返回\n参数可以是多个线程句柄,或包含多个线程句柄的table\n可选使用最后一个参数指定超时值(毫秒)
thread.waitClose(__) = 等待一个或多个线程返回,并释放所有线程句柄\n参数可以是多个线程句柄,或包含多个线程句柄的table
end intellisense*/ 

//io.open共享模式参数
 /**intellisense()
_SH_DENYRW=@0x10/*独占读写*/
_SH_DENYWR=@0x20/*独占写*/
_SH_DENYRD=@0x30/*独占读*/
_SH_DENYNO=@0x40/*共享模式*/
_SH_SECURE=@0x80/*安全模式*/
end intellisense**/

/*intellisense(::)*/
::CopyMemory = Kernel32.api("RtlMoveMemory","void(POINTER Destination,pointer Source,INT size)" ) ;
::CopyMemoryByStruct = Kernel32.api("RtlMoveMemory","void(POINTER Destination,struct Source,INT size)" ) ;
/*end intellisense*/

 raw.mixin = function(p,s,v,...){
 	if(v){
    	raw.convert(p, s);
    	table.mixin(s,v,...)
    }
    CopyMemoryByStruct(p, s, raw.sizeof(s));
    return s;
}
 
namespace math{ 
	mulDiv = ::Kernel32.api( "MulDiv", "int(int a,int b,int c)"); 
}
 
/**intellisense()
raw.mixin(.(指针,结构体对象,任意个混入对象) = 混入新的值,支持任意个混入table对象,\n自动更新指针指向内存,并返回结构体对象\n注意不可将AAuto中的字符串混入结构体中,\n以防止外部函数使用析构无效的字符串指针
math.mulDiv(.(a,b,c) = 返回a乘b再除以c的结果,并自动四舍五入转为整数\n可尽量使运算不会溢出,运算错误则返回-1
math.round(.(数值,精度) = 四舍五入,\n精度指定小数后的位数,默认为0(取整)
end intellisense**/

__beforeUnload =  function(){
	if( win[['form']] ){ 
		for(hwnd,winform in win.form._forms){  
			::DestroyWindow(hwnd); 
		}; 
	}
	if(beforeUnload)beforeUnload();
}

/**intellisense()
beforeUnload = @import util;\nutil.connect( ,"beforeUnload",function(){\n	__\n} );
end intellisense**/
