语言

DWORD是无符号的

今天刚知道。一直都以为DWORD就是long,没想到它是unsigned long。

具体定义在WinDef.h中:

typedef unsigned long DWORD;

更多的Windows数据类型可以在这里查。

强大的批处理 (4) 使用数组

批处理指令中并没有原生支持数组,但这不代表不能模拟出来。

来看下面的代码:

SET Obj_Length=2

SET Obj[0].Name=Test1
SET Obj[0].Value=Hello World

SET Obj[1].Name=Test2
SET Obj[1].Value=blahblah

这样就定义了一个数组了,而且是结构体的数组。

在需要取值的时候,可以这么玩:

SET Obj_Index=0

:LoopStart
IF %Obj_Index% EQU %Obj_Length% GOTO :EOF

SET Obj_Current.Name=0
SET Obj_Current.Value=0

FOR /F "usebackq delims==. tokens=1-3" %%I IN (`SET Obj[%Obj_Index%]`) DO (
    SET Obj_Current.%%J=%%K
)

ECHO Name = %Obj_Current.Name%
ECHO Value = %Obj_Current.Value%
ECHO.

SET /A Obj_Index=%Obj_Index% + 1

GOTO LoopStart

输出结果:

Name = Test1
Value = Hello World

Name = Test2
Value = blahblah

怎么样,很不错吧~~

在C#中使用@声明变量 – 逐字标识符

在C#中,@符号不仅可以加在字符串常量之前,使字符串不作转义之用,还可以加在变量名之前,使变量名与关键字不冲突,这种用法称为“逐字标识符”。请看下面的代码:

class @class
{
    public static void @static(bool @bool) {
        if (@bool)
            System.Console.WriteLine("true");
        else
            System.Console.WriteLine("false");
    }
}

这里使用到@的地方有三处,@class,@static和@bool,如果不加@的话,他们都是关键字,编译就会报错。加了@之后,他们和普通的变量名没有区别了,可以正常使用。当然@也可以加在非关键字之前,比如:

static void Test(string @str)
{
    Console.WriteLine(str);
}

这样@就一点效果也没有,@str等价于str。

当然,使用关键字作为变量名是非常不推荐的,除非特殊情况,比如和其它语言交互,一般不鼓励使用。

强大的批处理 (3) 判断目录在%Path%中

貌似没有很优美的做法,只能把%Path%按分号分割,然后一段一段地比较。

:InPath [In]Path [Out]0/1
SETLOCAL
SET LocalPathCopy=%PATH%
SET Result=0
:WHILE
IF "%LocalPathCopy%" == "" GOTO WEND
FOR /F "delims=;" %%I IN ("%LocalPathCopy%") DO (
    IF /I "%%~I" == "%~1" (
        SET Result=1
        GOTO WEND
    )
)
FOR /F "delims=; tokens=1,*" %%I IN ("%LocalPathCopy%") DO (
    SET LocalPathCopy=%%~J
)
GOTO WHILE

:WEND

:InPathRet
ENDLOCAL & SET %2=%Result% & GOTO :EOF

使用方法:

SET x=C:\Windows
Call :InPath %x% Result
IF %Result% == 0 SET Path=%Path%;%x%

在命令行中以管理员权限启用应用程序

自从Vista带来了UAC之后,应用程序就变成了两种,有管理员权限的,和没有管理员权限的。一些老的应用程序会莫名其妙地出错,这时候就要考虑右击应用程序,然后“以管理员身份运行”。这还不是什么大问题,exe文件的右键菜单里都会有这个,但是对于一些脚本文件(cmd, js一类)来说,就没那么方便了。通常需要重新开一个带管理员权限的命令行窗口,然后打很多cd回到刚的文件夹,然后再运行脚本,相当麻烦。

搜了一下,找到一个解决办法。把下面的代码保存为Elevate.js:

var command = WScript.Arguments.Item(0);
var argument = "";
for (var i = 0; i < WScript.Arguments.Count(); ++i){
    argument += WScript.Arguments.Item(i) + " ";
}

try{
    var shellapp = new ActiveXObject("Shell.Application");
    shellapp.ShellExecute(command, argument, null, "runas", 1);
}
catch(e){
    WScript.Echo("Something wrong: " + e.description);
}

以后要以管理员身份运行程序的时候,只要输入“Elevate <exefile> <arguments>”就可以了,比如“Elevate cmd /k”。

当然,这个逃不过UAC的检查,还是会有一个对话框弹出来要点“确定”的。

强大的批处理 (2) Fibonacci函数

小无聊一下,不过真的很强大……

@ECHO OFF

SETLOCAL

SET X=10

CALL :Fib %X% Y
ECHO Fib^(%X%^)=%Y%
GOTO :EOF

:Fib [In]X [Out]Result
SETLOCAL
SET A=%1
SET D=1
SET E=0

IF %A% LEQ 1 (
    GOTO FibRet
)

SET /A B=%A%-1
SET /A C=%A%-2
CALL :Fib %B% D
CALL :Fib %C% E

:FibRet
ENDLOCAL & SET /A %2=%D%+%E% & GOTO :EOF

输出是“Fib(10)=89”

强大的批处理 (1) 字符串截取

获取当前的小时数:

@ECHO OFF

SET Hour=%TIME:~0,2%

IF %Hour% GTR 12 (
    ECHO Afternoon
) ELSE (
    ECHO Morning
)

打印Windows的版本:

@ECHO OFF

FOR /F "tokens=1,2,3,4" %%I IN ('VER') DO (
    SET Ver_Temp=%%L
)

SET Ver_Major=%Ver_Temp:~0,1%
SET Ver_Minor=%Ver_Temp:~2,1%
SET Ver_Build=%Ver_Temp:~-5,4%

ECHO Windows Version:
ECHO   Major %Ver_Major%
ECHO   Major %Ver_Minor%
ECHO   Build %Ver_Build%

C#中重载相等运算符

运算符重载一直是一个很诡异事情,因为在写代码的时候,不知道某个运算符有没有被重载过。在C++里面,运算符重载可以写在类的外面,当intellisense不工作的时候,找到一个运算符的重载函数是一件相当头疼的事情。这个问题在C#中改善了不少,因为运算符重载一定要写在类内,而且intellisense很强大。不过另一个问题又产生了……

先来看C++中的“==”重载:

struct A{
    int x;
    int y;
};

inline
bool operator == (const A& a, const A& b){
    return a.x == b.x && a.y == b.y;
}

上面这段代码中,由于声明的关系,a和b永远不可能为NULL,所以直接调用a.x和b.x是没有问题的。

而在C#中:

struct A
{
    public int x, y;
    public static bool operator ==(A a, A b)
    {
        return a.x == b.x && a.y == b.y;
    }
    public static bool operator !=(A a, A b)
    {
        return !(a == b);
    }
}

这段代码是没问题的,因为A是struct,而struct不可能为null。但换成class就有问题了,比如:

    class A
    {
        public int x, y;
        public static bool operator ==(A a, A b)
        {
            if (a == null && b == null)
            {
                return true;
            }
            if (a == null || b == null)
            {
                return false;
            }
            return a.x == b.x && a.y == b.y;
        }
        public static bool operator !=(A a, A b)
        {
            return !(a == b);
        }
    }

由于reference type可以为null,所以要先检查a和b是不是null,但是“a == null”这一句又会去调用“operator ==”,于是就无限递归下去了……想了很久都没想出来变通的方法,而且System.String的实现也很诡异:

public static bool operator ==(string a, string b)
{
    return Equals(a, b);
}
public static bool Equals(string a, string b)
{
    return ((a == b) || (((a != null) && (b != null)) && EqualsHelper(a, b)));
}

看上去也会无限递归的(Reflector出来的,不一定准),很神奇……

虽然对于Referece type不建议重载==,但是不建议并不代表不能用吧,这个设计太挫了……

Javascript学习心得

这几天做Ajax,顺便研究了一下Javascript,发现以前对Javascript是完全不了解=.=

总结如下(以下简称Js):

1、Js中没有Class,只有Function,一个Function可以看成一个类的构造函数,new Function即new Class。每个Function有一个对象prototype,new Function的时候,自动把这个Function的prototype复制到新的对象中。

2、Function中可以使用this关键字,指代的是包含这个Function的类,不过this是动态绑定的,比如

var x = {
    value:"x",
    a:function(){
        alert(this.value);
    }
};
var y = {
    value:"y",
    a:x.a
};
y.a();

运行结果是y。这种模式在Lua中见过,如果要让运行结果是x,要对x.a做一个Binder,显示指定this为x,并调用a.x.apply(obj, …)。

3、Js中没有继承,要实现继承的功能,有N种比较猥琐的方法。一种是在新的对象中放一个base指针,指向它的父类。还有一种是复制prototype。不过看上去都很恶心。以前看过Lua中有一种继承的方法是做一个索引表,调用函数的时候查找它父类的函数,不过Js不支持运算符重载=.=

4、Js中唯一的网络组件是XMLHttpRequest,在IE7和Firefox 中可用,IE6要用new ActiveXObject(“Msxml2.XMLHTTP”)。XMLHttpRequest可以产生一个异步通讯的线程,是Ajax的主要工具之一。线程的管理依赖于浏览器,具体的说明可以看Ray的一篇文章

5、Js中数值0等价于false,也就是if (0){}等价于if (false){},在写Array.Contains的时候总算明白了为什么Lua中0不等价于false,因为Array.Contains可以返回null表示没有找到,而调用的时候可以写If (obj.Contains(val)){},而不用写if (obj.Contains(val)!=null){},但是Js中就只有写后一种了=.=

6、Js中有delete关键字,但不是用来进行垃圾回收的,只能用来在类中删除一个元素。垃圾回收是自动的。

7、Js中有很多保留字(因为ECMA规范的缘故),比如class,IE7会认为var class=0是错误而停止执行。

8、Firefox中的String重载了[]运算符,等价于charAt,但这不是标准。

9、Js和Java同宗,N多相似的地方,比如Date中月份从0开始,0表示一月;String是不可变类;函数的命名和Java几乎完全相同。

10、Firefox下不允许修改Object.prototype,而IE下可以。

先写到这,以后再补……