Posted on 24-06-2010
Filed Under (技术) by waterlin

最近一直在做 Windows Mobile 的移动开发,重装系统后,用 Visual Studio 2005 死活没有办法新建工程。

仔细地找了找答案,原来需要打上 Visual Studio 2005 SP1 的补丁才行!

另外,做 M8 的开发,也需要用上 Visual Studio 2005 SP1 才行,否则连 Samples 都编译不过。

(0) Comments    Read More   
Posted on 17-04-2010
Filed Under (技术) by waterlin

在 Windows 的 Shell 脚本里,如果想用当前的日期和时间来作文件名,可以用下面的方法:

  1. 先得到当前日期和时间的字符串;
  2. 再分割出想要的字符;
  3. 最后再拼接成一个完整的文件名。

例子代码如下:

echo %DATE%
echo %TIME%
set  datetimef=%date:~-4%_%date:~3,2%_%date:~0,2%__%time:~0,2%_%time:~3,2%_%time:~6,2%
echo %datetimef%

在英文 Windows 环境下,输出可能是这样:

13/04/2010
11:00:43.31
2010_04_13__11_00_43

如果是在中文环境下,可能需要根据系统的日期、时间格式等,对字符串处理作一些简单的处理。

(0) Comments    Read More   
Posted on 02-09-2009
Filed Under (技术) by waterlin

之前文章中提到的通过 Windows 注册表来实现开机时文件替换的方法,好像只对位于同一个文件分区的两个文件有效,而对于两个处在不同文件分区的文件,则没有办法。

举例来讲,我想用 E 盘下的 test1.txt 文件来替换掉 C 盘下的 test2.txt 文件,按之前的方法,在注册表里写入下面的值:

\??\e:\test1\test1.txt
!\??\c:\test2\test2.txt

重启电脑后,test1.txt 文件不见了,但文件 test2.txt 的内容并没有被 test1.txt 成功替换掉。

我反复试验了很多次都不行,最后的结论是,这种通过 Windows 注册表来实现开机时文件替换的方法,的确不能应用于不同的文件分区。以后在使用前面介绍过的方法的时候,一定要注意这一点。

我唯一想的原因是:在重启的时候,Windows 并不是真正的在做复制、删除文件等操作,它很有可能只是把被替换文件链接到替换文件上并修改名称,硬盘分区里的大部分数据其实没有移动,因此,在两个不同的分区里,就自然没有办法了。

有谁知道原因的,不妨告诉我,多谢了~~

(0) Comments    Read More   
Posted on 28-08-2009
Filed Under (技术) by waterlin

昨天在用 C++ 操作 Windows 注册表(Registry)的时候,犯了一个非常低级的错误,现在把有关注册表的一些相关知识写下来,以免再犯。

1. 注册表的基本概念

Windows 的注册表中包含了 Windows 的系统配置、PC机的硬件配置、Win32应用程序和其他设置信息。注册表和 INI 文件不同,它是多层次的树状数据结构,具有六个分支(根键),每个分支又由许多的键(key)和值(value)组成,每个键则代表一个特定的配置项目。在注册表中,键可以包括子键(sub key)和值(value)。我们可以对它们做个比喻,键就是目录,而子键和值可以看成子目录和文件,这样比喻虽然不准确但是很形象。

2. 注册表里值(value)的数据类型

注册表里的值(value)可以是字符串、多字符串或是二进制值等,详细的解释可以看看MSDN上的相关解释

3. 写入多字符串类型数据时容易犯的错误

我在注册表编辑器里,在一个键下面直接新建了一个多字符串(REG_MULTI_SZ)的值,编辑该值的时候,输入完一个字符串就用回车来分隔,输了几行,就成了下面的情形:

REG_MULTI_SZ_editCopyright.png

测试完我该输入的东西后,我就开始用C++编码来实现这个步骤、让它自动化。

在编码需要一次性插入到多字符串(REG_MULTI_SZ)值里的多个字符串时,我就想当然地以为是用回车来分隔这若干个字符串(因为前面我在编辑器里就是用回车来分隔的嘛),于是在代码里把”\r\n”放在两个字符串之间。

但是,在测试代码的时候,用”\r\n”写出来的字符串,与之前手动编辑时添加回车的结果完全不一样。我找了很久原因,最后通过对比注册表值的二进制编码,才发现了原因。

REG_MULTI_SZ_edit2Copyright.png

REG_MULTI_SZ_edit3Copyright.png

其实,注册表里的多字符串(REG_MULTI_SZ)值是用NULL来分割的。在注册表编辑器里手动编辑后,有”\r\n”的地方自动被更替换成了”"。因为规定了注册表里的字符串(REG_SZ)只能以一个空的字符结束,多字符串则需要以两个空字符串结束。当然,真正的规则稍微复杂一些,看MSDN里有关多字符串的说明:

A sequence of null-terminated strings, terminated by an empty string ().

The following is an example:

String1String2String3LastString

The first terminates the first string, the second to the last terminates the last string, and the final terminates the sequence. Note that the final terminator must be factored into the length of the string.

The values are separated by null characters and terminated by an empty string.

4. 注册表里值的大小是有限制的

放到注册表里的值不能超过2048 bytes,如果超过这个大小,最好存放在文件里,然后让注册表去读这个文件:

Value sizes are limited by available memory. Long values (more than 2048 bytes) should be stored as files with the file names stored in the registry. This helps the registry perform efficiently. Application elements such as icons, bitmaps, and executable files should be stored as files and not be placed in the registry.

5. 用MoveFileEx()并且带上MOVEFILE_DELAY_UNTIL_REBOOT的参数,也可以实现通过Windows注册表来实现开机时文件替换

这个页面里也有更多有关重启系统替换文件的知识。

6. 常用的注册表API函数有RegOpenKeyExRegQueryValueExRegSetValueEx等。

要判断一个Value是否存在于某个键下面,可以使用RegQueryValueEx函数,如果返回的是ERROR_FILE_NOT_FOUND,则表明该值不存在。

7. Windows 的 API 并不提供在一个值后面追加值的方法,如果你要在原来的值后面追加一个值,则你只能把这个值读出来、追加,然后再写入。

(1) Comment    Read More   
Posted on 26-08-2009
Filed Under (技术) by waterlin

1. 为什么需要通过注册表来实现开机时文件替换?

有一些文件,被系统的一些服务所独占,我们在热备份与热恢复系统的时候,没有办法直接替换掉。

也有一些程序以独占的方式(exclusive access)打开某个文件,在这个程序退出之前,按常规的方法,我们是不能替换掉这个文件。

这些情况下,我们可以通过注册表 (Windows Registry) 记录下需要替换的文件等相关信息,在下一次开机、应用程序启动之前进行替换掉。

2. 具体的实现方法

记得在进行以下步骤之前,先备份一下你的注册表

下面就以用放在目录 C:\Temp 下的 Win32k.sys 文件,替换系统目录 %SystemRoot%\System32 下的 Win32k.sys 文件为例,详细介绍一下利用注册表来实现开机替换文件的操作。你可以通过这种方法来替换掉你 Windows 系统里的任何文件,当然,你的 Windows 应该是要能启动的。

  1. 启动注册表编辑器 (regedit.exe);

  2. 按下面的路径,在注册表里找到相关的key:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager

  3. 在 Session Manager 这个注册表目录下,通过以下方式新建一个值 (value):

    值名称(Value name):
        PendingFileRenameOperations

    类型(Data type):
        REG_MULTI_SZ(多字符串值)

    值数据(Value data):
        \??\c:\temp\win32k.sys
        !\??\c:\winnt\system32\win32k.sys

    这里要特别注意,一定要分两行来填写值(填完后在注册表里会显示成一行),并且那个”!”必须放在第二行的开头。

    这种表达方式是用前面路径的文件来代替后面路径的文件。

  4. 退出注册表编辑器;

  5. 重新启动系统。

重启 Windows 系统后,如果第二个文件存在,则会把第一个文件的内容替换到第二个文件里,第二个文件的文件名保持不变,并且删除第一个文件;如果系统里原来就没有对应的第二个文件,则系统会自动新建一个和第二个文件名一模一样的文件,再把第一个文件里的内容拷贝进去。替换动作完成后,系统会自动清除注册表里添加的 PendingFileRenameOperations 值。

如果是要批量替换多个文件,则只需要按上面的值数据形式,在注册表变量值数据里添加要替换的多个文件信息即可,例如:

\??\c:\test2\test2.txt
!\??\c:\test1\test1.txt
\??\c:\test2\test22.txt
!\??\c:\test1\test11.txt

如果你的机器用上面的办法替换文件出错,则重点检查上面第三步的表达式是否有误。

除了往注册表里塞东西这个方法以外,你还可以使用Windows自带的mv.exe工具,或是下载与使用Inuse.exe工具,这些工具的详细使用方法,可以看帮助说明。

(2) Comments    Read More   
Posted on 13-08-2009
Filed Under (技术) by waterlin

在VC++ 2005里,有一个Start Page标签页面,方便你在不同的工程里进行切换而不需要重启VC++ 2005。

如果你不小心关掉了Start Page页面,可以用这个方法再打开这个页面:

View –> Other Windows –> Start Page

(0) Comments    Read More   
Posted on 11-08-2009
Filed Under (技术) by waterlin

Windows的VSS是指给磁盘打快照的服务,可以方便实施热备份等,MSDN里的相关文档有着详细地介绍。

下载VSS SDK包,这个安装包的安装路径默认为:

C:\Program Files\Microsoft\VSSSDK72\

当然,如果你的VSS版本号不太一样的话,路径会有所区别。

SDK自带了几个例子,对我们熟悉VSS非常有帮助,放在SDK安装路径下的TestApps目录,如果为默认安装,则是:

C:\Program Files\Microsoft\VSSSDK72\TestApps

不过我在Visual Studio 2005里编译vshadow这个例子工程时,编译器提示类似如下错误:

error C4430: missing type specifier – int assumed. Note: C++ does not support default-int e:\watercode\vsssamplecode\testapps\vshadow\src\shadow.cpp 30

这是因为VS 2005的C++编译器严格地检查函数的返回值,无返回值函数的返回值不再默认为整数,因此,可以修改main函数的定义,使之返回一个整数值来解决这个编译问题:

把shadow.cpp文件里的主函数

extern “C” __cdecl wmain(int argc, WCHAR ** argv)

根据需要改为类似于

int wmain(int argc, WCHAR ** argv)

即可。

(0) Comments    Read More