本帖最后由 happy886rr 于 2017-2-22 11:13 编辑
无意中百度到了微软WINDOWS nt4的源码,见CSDN下载链接http://download.csdn.net/detail/qbgao/3900606,发现该源码是几乎非常完整的,包括基础dll的实现,内核的实现,cmd的实现都是完全可以编译。所以就在此基础上,结合wine的源码等多个开源项目,东拼西凑,耗时数小时,DIY了一个ICMD.EXE,其中编译需要用到20年前的库文件真是难搞。
此次DIY重点集成了原生API调用的功能,通过set /f开关实现。同时附送一个set /i开关方便批处理科学计算使用。小打小闹,源码几乎都是别人泄露的,我只把自己的revpolish计算器和一些小的修改加入,修复了一些大小写的问题,进行了多处代码改良,杂交,所以兼容性也可以,还有wine的影子。总之各种成分拼起来能用。
COPYRIGHT@2017~2019 REWRITE BY HAPPY, VERSION 1.0
ICMD.EXE
摘要:
=============================================================================
ICMD脚本解释器,时间仓促只增加了一小部分功能,就是set/i和set/f开关。
=============================================================================
下载地址
用法:
-----------------------------------------------------------------------------
ICMD [使用手册]
-----------------------------------------------------------------------------
首先在批处理最顶端加上ICMD调用头
@IF [%1]==[] ("%~DP0ICMD.EXE" /C "%~F0" 1&EXIT)&::ICMD SCRIPT 2017~2019
然后基本语法同CMD.EXE,主要区别在于SET增加了 /I、/F开关
一、原生浮点计算开关SET /I
SET /I [结果值]=[浮点数学表达式]
-----------------------------------------------------------------------------
REM 增加原生浮点科学计算开关SET /I (使用自主研发的revpolish静逆波兰解析器)
set /i a=sin(torad(30)+cos(tan(3)))/7*6+exp(5)
echo %a%
-----------------------------------------------------------------------------
二、原生API调用开关 SET /F
SET /F [返回值]=[函数名] [参数] [参数] ...
-----------------------------------------------------------------------------
REM 普通字符串前加A作为标识,宽字符串前加L。如 L"1.ico"标识宽字符的 "1.ico",
其他类型无需任何标识。
REM 一次把所有DLL都动态链入,省得每次呼叫。
set/f =LinkDllW L"USER32" L"KERNEL32" L"GDI32" L"GDIPLUS" L"MSVCRT"
set/f hIcon=LoadImageW 0 L"1.ico" 1 0 0 16
set/f hCMD =GetConsoleWindow
set/f hDC =GetDC %hCMD%
set/f =DrawIconEx %hDC% %x% 0 %hIcon% 128 128 0 0 3
-----------------------------------------------------------------------------
备注:
-----------------------------------------------------------------------------
REM 由于源码比较古老,利用了VC98编译器的库文件才得以编译。完全抛弃 DLLCALL、
的古老模式。用最简洁的语法,调用C的函数。
抛弃了C语言的数据类型,只有字符串需要加标识符,ANSI字符串前加A,宽字符串前加L。
其他类型无需任何数据类型标识。
-----------------------------------------------------------------------------
支持的计算函数
-----------------------------------------------------------------------------
常数类
pi 3.1415926535897932
e 2.7182818284590452
通用类
rand 随机数
round 四舍五入
int 取整
ceil 向上舍入
floor 向下舍入
abs 绝对值
sqrt 开方
lg 常用对数,以10为底
ln 自然对数
exp e的次幂
gamma 伽玛函数
deg 度转弧度
+ 加
- 减
* 乘
/ 除
% 取余数
^ 次方
! 阶乘
三角函数类
sin、cos、tan
arcsin、arccos、arctan
双曲函数类
sinh、cosh、tanh
arcsinh、arccosh、arctanh
-----------------------------------------------------------------------------
基本上取代了dll cll和capi。兼容95年后的各种windows带窗口的系统。我还在diy中,后续会改造出更强大的cmd新语法。
API调用格式更是简单到极点。
SET /F [返回值]=[函数名] [参数] [参数] ...- @echo off
- set/f=LinkDllW L"USER32" L"KERNEL32"
- set/f=MessageBoxW 0 L"你好" L"message" 1
- pause
复制代码 弹窗如此简单。
源码解读,在winNT的cenv.c中是set 命令的实现方式,我定位到如下地方- struct cmdnode *n ;
- {
- TCHAR *tas ; /* Tokenized argument string */
- TCHAR *wptr ; /* Work pointer */
- int i ; /* Work variable */
-
- //
- // If extensions are enabled, things are different
- //
- if (fEnableExtensions) {
- tas = n->argptr;
- //
- // Find first non-blank argument.
- //
- if (tas != NULL)
- while (*tas && *tas <= SPACE)
- tas += 1;
-
- //
- // No arguments, same as old behavior. Display current
- // set of environment variables.
- //
- if (!tas || !*tas)
- return(DisplayEnv()) ;
-
- //
- // See if /A switch given. If so, let arithmetic
- // expression evaluator do the work.
- //
- if (!_tcsnicmp(tas, SetArithStr, 2))
- return SetArithWork(tas+2);
-
- //
- // See if first argument is quoted. If so, strip off
- // leading quote, spaces and trailing quote.
- //
复制代码 注意到- if (!_tcsnicmp(tas, SetArithStr, 2))
- return SetArithWork(tas+2);
复制代码 其中SetArithStr就是_TEXT("/A")照猫画虎,自己增加了一个开关_TEXT("/I"),其中的SetIRevpolish来自自己开发的静逆波兰计算器,以便实现浮点科学计算,链接http://www.bathome.net/thread-42830-1-1.html。- if (!_tcsnicmp(tas, _TEXT("/I"), 2))
- return SetIRevpolish(tas+2);
复制代码 在增加开关_TEXT("/F")- if (!_tcsnicmp(tas, _TEXT("/F"), 2))
- return SetICallAPI(tas+2);
复制代码 然后自己写个实现就搞定了。NT4时代确实没有SET /P开关,但是自己增加就行,然后自己写个读取stdin流的函数,set/p就此搞定。if中的EQU,GET...不支持小写,加个||就完美了。- if (!_tcsnicmp(tas, _TEXT("/P"), 2))
复制代码 下面是开源项目wine的源码中关于cmd的核心部件,这个架构很 不错,就应该用switch来实现。- switch (i) {
-
- case WCMD_ATTRIB:
- WCMD_setshow_attrib ();
- break;
- case WCMD_CALL:
- WCMD_call (p);
- break;
- case WCMD_CD:
- case WCMD_CHDIR:
- WCMD_setshow_default (p);
- break;
- case WCMD_CLS:
- WCMD_clear_screen ();
- break;
- case WCMD_COPY:
- WCMD_copy ();
- break;
- case WCMD_CTTY:
- WCMD_change_tty ();
- break;
- case WCMD_DATE:
- WCMD_setshow_date ();
- break;
- case WCMD_DEL:
- case WCMD_ERASE:
- WCMD_delete (p, TRUE);
- break;
- case WCMD_DIR:
- WCMD_directory (p);
- break;
- case WCMD_ECHO:
- WCMD_echo(&whichcmd[count]);
- break;
- ....
- ....
- default:
- WCMD_run_program (whichcmd, 0);
- }
复制代码
|