An Underestimated Tool in Windows: HTA (HTML Application)

I can’t find a convinced source telling in which specific date did HTA become available, but it seems to be earlier than the year 2000.

On the official introduction page of HTA, there’s a highlight saying “The Power of Trust”. Unlike normal HTML pages running in a normal browser, HTA can have almost the same permissions that an exe file could have. Which gives it access to varieties of ActiveX that are not available in normal browsers due to security reasons.

I am always wondering why only a few people know and use HTA? Hmm, maybe one of the reasons is its “Microsoft” tag. I have given up the thoughts hoping HTA could be relatively mainstream, however, for developers who use JavaScript and HTML, HTA could still be a good choice to write some lite productive tools for your colleagues and yourself.

NodeJS would certainly have much better ecosystem now but for some specific tasks I still prefer tools with GUI… T-T (Now I also use NodeJS to do some batch work.)

But it was a shame that Microsoft stopped making it better. Wishes.

Windows 7 开机以管理员身份启动应用程序

这个也是最近做的代理整合软件过程中遇到的问题, 因为要修改Internet Settings, 可能还有其他一些操作, 需要有管理员权限, 强制程序使用管理员权限可以添加一个manifest文件, 再将其中的requestedExecutionLevel, level改为”requireAdministrator”即可. 其实当时做到这里, 我以为就大功告成了, 但重启之后发现程序没有启动, 搜了搜, 才知道是自动启动的家伙获取不了管理员权限.

最后找到的解决方法有二, 一个是先启动一个不需要管理员权限的程序, 再延时打开需要管理员权限的程序, 不过效果不理想, 也不知道延时多久才能搞定. 并且, 每次开机都会请求权限, 用户用着也不爽. (话说, 关了UAC多好… 这儿整个都不用了.)

后来发现了Task Scheduler(任务计划)这个东西, 顿时觉得捡到了宝, 于是继续查找各种资料, 发现不仅能启动, 还能以管理员权限启动. 不过貌似只能用在Windows Vista/7 上(XP上貌似也有任务计划, 但可能接口不同或者没这么强大吧, 这个我没有细查, 但代码在XP上的确会进入catch), 所以XP上还要优雅降级, 添加普通的开机启动项, 反正XP又没有UAC, 是吧.

我使用的是C#, 同时需要添加COM引用, TaskScheduler 1.1 Type Library, 在system32目录下的taskschd.dll. 代码如下:

var dir = @”SOFTWARE\Microsoft\Windows\CurrentVersion\Run”;
try {
    var scheduler = new TaskSchedulerClass();
    scheduler.Connect(); //连接, 还有一些登录参数可选.
    var task = scheduler.NewTask(0); //官方文档上, 这个参数后面加了注释reserved.
    task.RegistrationInfo.Author = “Pacgen”;
    task.RegistrationInfo.Description = “Start Pacgen with Windows”;
    task.Settings.Enabled = true; //or false, 开关.

    //在启动的时候执行, 一开始只写了Logon, 不过发现开机的时候登录并没有触发.
    task.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_BOOT);
    //注销后登录什么的.
    task.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_LOGON);
    var action = task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC) as IExecAction;
    //上面的Triggers.Create也会像Actions.Create一样分别返回类型为IBootTrigger, ILogonTrigger的对象(自己as或者强制转换一下).
    //可以做更多设置.

    //这里就是设置为用户能达到的最高权限.
    task.Principal.RunLevel = _TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
    action.Path = Application.ExecutablePath; //需要启动的程序路径.
    action.Arguments = “background”; //参数.

    var folder = scheduler.GetFolder(@”\”); //这里是Task的根文件夹, 还可以用folder.CreateFolder来创建自己的目录.

    //注册任务. 这里的TASK_LOGON_INTERACTIVE_TOKEN就是说使用用户当前的登录信息(如果已经登录).
    folder.RegisterTaskDefinition(“PacgenStartup”, task, (int)_TASK_CREATION.TASK_CREATE_OR_UPDATE, null, null, _TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN);

    //注册成功, 删除注册表内的启动项, 这里的SetRegister是我自己写的, 替换掉即可.
    //SetRegistry(dir, “Pacgen”, null);
}
catch {
    //注册失败, 添加开机启动项.
    //SetRegistry(dir, “Pacgen”, settings.AutoStart ? “\”” + Application.ExecutablePath + “\” background” : null);
}

现在程序就能悄无声息地以管理员权限启动了, 连请求用户都免了. 开心.

最后附上官方说明: http://msdn.microsoft.com/en-us/magazine/cc163350.aspx