2
Posted on 下午11:50:00 by Fan Zhang and filed under

  一些动物的图片,有山羊、河马、北极熊...

  大部分是在煎蛋上看的。

  元旦了,祝大家身体健康,工作顺利,学习进步。

4
Posted on 下午10:47:00 by Fan Zhang and filed under

  最近真是太忙,昨天连觉都没睡。手里文章已经积压了好几篇没写了。

  想不到已经两年了,虽然很多文章自娱自乐的成分较多,但是非常感谢阅读我 Blog 的朋友,祝圣诞快乐~

5
Posted on 下午9:37:00 by Fan Zhang and filed under ,

  搜狗推出了浏览器,当然是 IE 内核。我觉得软件做得还行。

  重点是内含代理,可以使教育网免费出国,的确是可以的。只是不知道是否是搜狗自己架设的服务器,如果是,那就可能用的人多的时候不太好使。

  其实,我觉得在浏览器中加入教育网增强是好的,只是应该以插件形式。不然可能会损失一部分不在教育网,又有"软件洁癖"的人...

  如果浏览器能搞成类似 Tor 的网络形式,可能能从根本上优化浏览速度。但是,估计就要被墙了。

0
Posted on 下午11:00:00 by Fan Zhang and filed under

  今天去东三环的国展参观了中国国际社会公共安全产品博览会(CIEC),主题是平安城市。有非常多的参展公司,Sony、三星、海康等等。涉及的领域有:摄像设备(摄像机、云台),配套的管理平台(硬盘录像机、视频服务器、显示设备),还有入侵报警的传感器以及软件,安检设备,生物特征识别设备等等。

  不同厂商所做的工作也不同,有的是做芯片的,有的是做摄像头等设备的,有的是做智能监控软件,还有是做身份认证系统的。

  感觉挺有意思,也很受启发。只是我去的时候已经是最后一天,下午一点的时候就往外赶人了。

  Sorry,本次无图...

1
Posted on 下午3:31:00 by Fan Zhang and filed under ,

  近期,有关搜索引擎的问题被报道很多,包括 CCTV 也曝光百度的竞价排名。但是令我很不解的是,经常有媒体在转载过程,或者自己的报道过程中把 Google 也牵扯进来。我不想举出这些文章的来源、转载过程等等,相信对新闻关注的人早已发现了这个问题。

  不排除这些是媒体在某些部门(这个词真好用)授意下故意把打击面扩大的缘故。这也说明了,国家要加大对网络信息,尤其是搜索引擎的监管力度和方式。

  今天在 cnBeta 上看到李开复说:"我们预料到了近期可能会有关于谷歌相关不利报道",我觉得非常好笑。

  现在都在痛打搜索引擎上的虚假医药广告,我就想,CCTV 不也在黄金时段播放那些个"不太真实的"破广告吗?

  我一向都是支持国家政策的,我也理解新闻工作者为了增强导向性,为了增加收视率而做出的努力。但我厌恶那种为达目的不择手段的方式,故意做出假的画面,甚至移花接木、张冠李戴。

  回想了一下,Blog 上很多文章都是看了新闻报道有感而写下来的,其中有好几篇是在谈媒体本身的问题。比如:

  我关心媒体的道德问题,一个原因是这个的确很重要。我可以理解媒体应该起到正确的宣传教育和引导公众的作用。但是我希望,所使用的手段是合乎道德的,我想真实的报道应该是这个行业的底限吧?

  另外一个更重要的原因是,我很关心的人想要投身这个行业。我是一个理想主义者,我希望这里能保持它应有的纯洁。

  弄虚作假在什么地方都有,包括学术界,但是我不能默许它的存在。

3
Posted on 下午2:48:00 by Fan Zhang and filed under

  看很多人都在 Blog 上增加了 Google Friend Connect,我也想加一个。过程倒是非常简单,只要按照提示一步一步来就是,使用 Blogger 还不用上传文件,倒是很方便。

  只是,原本的 Friends 链接就重复了,和 Follower 的功能也有重复。所以决定都去掉...其实我好不容易才决定加上 Follower 的功能的...

5
Posted on 上午10:36:00 by Fan Zhang and filed under

  今天打开 Google Reader,发现眼前一亮,原本熟悉的界面变了。我第一反应是赶紧看了看 Greasemonkey 和 Stylish,发现没有修改什么啊,然后才反应过来,是改版了。(前一段时间 Gmail 增加了主题选择,让我对上述两个扩展的依赖也越来越小了。)

  这次 Google Reader 第一眼看上去,更加清爽和整洁。侧栏的颜色变浅,使人可以更加关注内容。侧栏中各个元素经过了重新设计和安排,显得更有结构,每一个导航条还可以收缩和展开,显得很贴心。

  以前我经常遇到 All items 和 Subscriptions 里面未读条目不同步的情况,一般我是分别刷新,现在新的界面左侧导航条的刷新按钮也变成了下拉菜单中的一项。

  虽然还有些不太习惯,不过很喜欢新的界面。期待提供类似 Gmail 的主题功能。我感觉,在阅读的时候,主要内容的焦点没有以前强烈(虽然淡化了侧栏的导航条),如果加入背景颜色(毕竟颜色太白会显得刺眼),或者一个更明显的边框可能更好一些。

  官方 Blog 文章: Square is the new round.

5
Posted on 下午4:04:00 by Fan Zhang and filed under ,

  之前曾经使用 VirtualBox 安装过 Ubuntu,现在因为测试需要,准备安装一下 Windows XP。

  结果一上来就遇到一个问题,在格式化一步出错,提示:Unable to allocate and lock memory...错误 ID:HostMemoryLow。原来是我把虚拟机的内存设置得太大了(设置的是 128M 好像,主机内存 1G+2G 页面缓存)。后来修改成 64M 就可以了。

  VirtutalBox 的虚拟硬盘是保存成 VDI 文件的,在虚拟系统运行的任何时刻,都可以生成一个当前系统运行状态的快照(Snapshots)。这个备份是保存在 Snapshots 目录下的一个新的 VDI 文件中,在快照生成之后的所有操作都是保存在这个新的 VDI 文件中,原始的文件就不会发生变化了。通过快速修复界面,可以恢复最近的快照。

  注意,当你新生成或者删除某一个快照备份的时候,原始的 VDI 就会发生变化,保存的是当前的系统状态。

  但是,VirtualBox 的快照恢复顺序类似与一个堆栈,只能恢复最近的快照,想要生成更早一点的状态,只能把最近的快照删除才行。这点也很好理解,因为如果想要并行保存两个状态,那势必要占用两份空间,而 VirtualBox 的快照是一个增量备份的过程,所以它只能线性恢复。

  而我们软件测试,是需要在同一个操作系统的不同软件环境下进行,比如需要保存刚刚安装完 Windows 的状态,还要保存已经安装常用软件的状态。这样就需要把虚拟硬盘的 VDI 文件多保存几份了。但是,直接复制 VDI 文件是不行的,因为 VirtualBox 对每个 VDI 文件有一个 uuid,所以直接复制以后无法注册,因为 uuid 是相同的。

  在帮助文件中给出了解决方案,就是通过命令行中使用 VBoxManage 的 clonevdi 的方法来复制一个 VDI 文件,并重新生成一个 uuid。使用方法如下,注意文件名如果有空格,需要用引号括起来。

VBoxManage clonevdi <uuid>|<filename> <outputfile>

  复制的过程相当慢...

  如何压缩虚拟硬盘的大小,在 VBoxManage 中有一个 modifyvdi compact 的命令,如果选用了动态分配磁盘,可以试试。注意到,因为在频繁的文件操作后,将会有大量的空间只被标记为删除,但是并没有真的清空。这样压缩就会没什么效果。

  一种方法是使用 Ghost 备份一下然后再恢复。另一种方法是:

  1. 首先进行磁盘碎片整理。
  2. 然后使用 Sysinternals 的一个命令行工具 SDelete,在 Guest OS 中执行:sdelete -c c:\ ,把C盘中标记为未使用的空间清0。
  3. 在 Host OS 中执行:VBoxManage modifyvdi "文件名.vdi" compact
4
Posted on 上午2:33:00 by Fan Zhang and filed under

  嗯...为了更好地学习与工作,我经过几天的酝酿,出手买了一台22宽的显示器:BenQ G2200W。

  本来想买 AOC 2217V 的,因为它性价比最高,也就是最便宜,但是实际看了几眼,感觉的确是一分价钱一分货。做工略显粗糙,漏光处理不好。

  最后买的这台 BenQ 其实也不怎么好,各项性能也一般,但是感觉稍微舒服一些。现在有 16:9 的型号,比如 BenQ T2200HD,分辨率可以达到 1920x1080,但是我感觉点距太小,平常编程或者文字处理会很不舒服。

  我的破旧的 9550 显卡还是能支持双显示器的。感觉不错,一边看电影,一边写文档,很自在。

4
Posted on 下午7:51:00 by Fan Zhang and filed under

  在 blogger 模板中有两个变量:data:newerPageTitle 和 data:olderPageTitle,一般显示在页面下方,是供翻页用的。

  其中 data:newerPageTitle 在中文环境下的内容为"较新的帖子",这是对的。但是 data:olderPageTitle 目前内容却为"帖子",应该翻译为"较旧的帖子"。

  我今天提交了这个问题,希望能尽快修正。

1
Posted on 下午1:37:00 by Fan Zhang and filed under , ,

  要编写一个类似于 Windows 任务管理器的软件,首先遇到的问题是如何实现枚举所有进程。暂且不考虑进入核心态去查隐藏进程一类的,下面提供几种方法。请注意每种方法的使用局限,比如使用这些 API 所需要的操作系统是什么(尤其是是否能在 Windows Mobile 下使用)。

  本文参考用户态枚举进程的几种方法,原文对于每一种方法都给出了完整的代码,被我照抄下来。还有一篇:如何用 Win32 APIs 枚举应用程序窗口和进程。基于我现学现卖的本质,对我演绎的部分请抱着批判的眼光来看,另外代码也没有充分验证。

使用 ToolHelp API

   ToolHelp API 的功能就是为了获取当前运行程序的信息,从而编写适合自己需要的工具(@MSDN)。它支持的平台比较广泛,可以在 Windows CE 下使用。在 Windows Mobile SDK 的 Samples 里面有一个 PViewCE 的样例程序,就是用这个来查看进程和线程信息的。

  使用方法就是先用 CreateToolhelp32Snapshot 将当前系统的进程、线程、DLL、堆的信息保存到一个缓冲区,这就是一个系统快照。如果你只是对进程信息感兴趣,那么只要包含 TH32CS_SNAPPROCESS 标志即可。

  然后调用一次 Process32First 函数,从快照中获取第一个进程,然后重复调用 Process32Next,直到函数返回 FALSE 为止。这样将遍历快照中进程列表。这两个函数都带两个参数,它们分别是快照句柄和一个 PROCESSENTRY32 结构。调用完 Process32First 或 Process32Next 之后,PROCESSENTRY32 中将包含系统中某个进程的关键信息。其中进程 ID 就存储在此结构的 th32ProcessID。此 ID 传给 OpenProcess API 可以获得该进程的句柄。对应的可执行文件名及其存放路径存放在 szExeFile 结构成员中。在该结构中还可以找到其它一些有用的信息。

  需要注意的是:在调用 Process32First() 之前,要将 PROCESSENTRY32 结构的 dwSize 成员设置成 sizeof(PROCESSENTRY32)。 然后再用 Process32First、Process32Next 来枚举进程。使用结束后要调用 CloseHandle 来释放保存的系统快照。

  以下为参考代码:

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

void useToolHelp()
{
    HANDLE procSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if(procSnap == INVALID_HANDLE_VALUE)
    {
        printf("CreateToolhelp32Snapshot failed, %d ",GetLastError());
        return;
    }
    //
    PROCESSENTRY32 procEntry = { 0 };
    procEntry.dwSize = sizeof(PROCESSENTRY32);
    BOOL bRet = Process32First(procSnap,&procEntry);
    while(bRet)
    {
        wprintf(L"PID: %d (%s) ", procEntry.th32ProcessID, procEntry.szExeFile);                                                  
        bRet = Process32Next(procSnap, &procEntry);
    }
    CloseHandle(procSnap);
}

void main()
{
    useToolHelp();
    getchar();
}

使用 Processing Status API

  在 Windows SDK 中可以找到 PSAPI,通过 PSAPI 可以获取进程列表和设备驱动列表。通过 EnumProcesses、EnumProcessModules、GetModuleFileNameEx 和 GetModuleBaseName 来实现。

  首先使用 EnumProcesses 来枚举所有进程,它有三个参数:DWORD 类型的数组指针 lpidProcess;该数组的大小尺寸 cb;以及一个指向 DWORD 的指针 cbNeeded,它接收返回数据的长度。DWORD 数组用于保存当前运行的进程 IDs。cbNeeded 返回数组所用的内存大小。下面算式可以得出返回了多少进程:nReturned = cbNeeded / sizeof(DWORD)。
  注意:虽然文档将返回的 DWORD 命名为“cbNeeded”,实际上是没有办法知道到底要传多大的数组的。EnumProcesses 根本不会在 cbNeeded 中返回一个大于 cb 参数传递的数组值。所以,唯一确保 EnumProcesses 函数成功的方法是分配一个 DWORD 数组,并且,如果返回的 cbNeeded 等于 cb,分配一个较大的数组,并不停地尝试直到 cbNeeded 小于 cb 。

  下面是参考代码:

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include "psapi.h"
#pragma comment(lib,"psapi.lib")


void PrintProcessNameAndID(DWORD processID)
{
    TCHAR szProcessName[MAX_PATH] = _T("<unknown>");
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS/* | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ*/,FALSE,processID);    
    //Process name.
    if(NULL!=hProcess)
    {
        HMODULE hMod;
        DWORD cbNeeded;
        if(EnumProcessModules(hProcess,&hMod,sizeof(hMod), &cbNeeded))        
        {
            GetModuleBaseName(hProcess,hMod,szProcessName,sizeof(szProcessName)/sizeof(TCHAR));                       
        }
    }
    wprintf(_T("PID: %d (%s) "),processID,szProcessName);
    CloseHandle(hProcess);
}

void main( )
{
    DWORD aProcesses[1024], cbNeeded, cProcesses;
    unsigned int i;
    if(!EnumProcesses(aProcesses,sizeof(aProcesses),&cbNeeded))
        return;
    cProcesses = cbNeeded/sizeof(DWORD);
    for(i=0;i<cProcesses;i++)
        PrintProcessNameAndID(aProcesses[i]);
    getchar();
}

  注意到,此方法由于需要进行 OpenProcess 操作,所以需要一定的权限,当权限不够时,有些进程将不能被打开。下面给出提升权限的相关代码:
void RaisePrivilege()
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if(OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hToken))
    {
        if(LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0].Luid))
        {
            AdjustTokenPrivileges(hToken,FALSE,&tp,NULL,NULL,0);
        }
    }
    if(hToken)
        CloseHandle(hToken);
}



使用 Native API

  在 使用Native API 探测本机系统信息 中我介绍了 Native API 中的 NtQuerySystemInformation(ZwQuerySystemInformation)。当设置查询的信息类型为  SystemProcessesAndThreadsInformation 时(第5号功能),可以用来枚举所有进程和线程。

  提醒:这个函数属于 Undocumented API,并且不建议使用,因为不同系统的结构和常量有所不同。下面列出 Windows XP 下可以用的相关结构和常量:

typedef DWORD (WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);

typedef struct _SYSTEM_PROCESS_INFORMATION
{
    DWORD NextEntryDelta;
    DWORD ThreadCount;
    DWORD Reserved1[6];
    FILETIME ftCreateTime;
    FILETIME ftUserTime;
    FILETIME ftKernelTime;
    UNICODE_STRING ProcessName;
    DWORD BasePriority;
    DWORD ProcessId;
    DWORD InheritedFromProcessId;
    DWORD HandleCount;
    DWORD Reserved2[2];
    DWORD VmCounters;
    DWORD dCommitCharge;
    PVOID ThreadInfos[1];
}SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

#define SystemProcessesAndThreadsInformation 5

  然后动态加载 ntdll.dll,获得函数的地址。便可以进行进程的枚举相关代码如下:
#include <windows.h>
#include <ntsecapi.h>
#include <stdio.h>

typedef DWORD (WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);

typedef struct _SYSTEM_PROCESS_INFORMATION
{
    DWORD NextEntryDelta;
    DWORD ThreadCount;
    DWORD Reserved1[6];
    FILETIME ftCreateTime;
    FILETIME ftUserTime;
    FILETIME ftKernelTime;
    UNICODE_STRING ProcessName;
    DWORD BasePriority;
    DWORD ProcessId;
    DWORD InheritedFromProcessId;
    DWORD HandleCount;
    DWORD Reserved2[2];
    DWORD VmCounters;
    DWORD dCommitCharge;
    PVOID ThreadInfos[1];
}SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

#define SystemProcessesAndThreadsInformation 5

void main()
{
    HMODULE hNtDll = GetModuleHandle(L"ntdll.dll");
    if(!hNtDll)
        return;
    ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll,"ZwQuerySystemInformation");
    ULONG cbBuffer = 0x10000;
    LPVOID pBuffer = NULL;
    pBuffer = malloc(cbBuffer);
    if(pBuffer == NULL)
        return;
    ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,pBuffer,cbBuffer,NULL);
    PSYSTEM_PROCESS_INFORMATION pInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;
    for(;;)
    {
        wprintf(L"PID: %d (%ls) ",pInfo->ProcessId,pInfo->ProcessName.Buffer);
        if(pInfo->NextEntryDelta == 0)
            break;
        pInfo = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo) + pInfo->NextEntryDelta);
    }
    free(pBuffer);
    getchar();
}
  
  对这个方法有问题的,可以参考我之前的那篇介绍 Native API 的文章。

  同样使用 ZwQuerySystemInformation 函数,查询类型如果设置为 SystemHandleInformation(第16号功能)也可以达到目的。它能获取系统中所有句柄,再加上进程 ID 的判断就可以枚举所有进程了。
#include <windows.h>
#include <ntsecapi.h>
#include <ntstatus.h>
#include <stdio.h>

typedef NTSTATUS (WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);

typedef struct _SYSTEM_HANDLE_INFORMATION
{
    ULONG ProcessId;
    UCHAR ObjectTypeNumber;
    UCHAR Flags;
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
}SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
    ULONG NumberOfHandles;
    SYSTEM_HANDLE_INFORMATION Information[1];
}SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;

#define SystemHandleInformation 0x10   //16

void main()
{
    HMODULE hNtDll = LoadLibrary(L"ntdll.dll");
    if(!hNtDll)
        return;
    ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll,"ZwQuerySystemInformation");
    ULONG cbBuffer = 0x4000;
    LPVOID pBuffer = NULL;
    NTSTATUS s;
    do
    {
        pBuffer = malloc(cbBuffer);
        if(pBuffer == NULL)
            return;
        memset(pBuffer,0,cbBuffer);
        s = ZwQuerySystemInformation(SystemHandleInformation,pBuffer,cbBuffer,NULL);
        if(s == STATUS_INFO_LENGTH_MISMATCH)
        {
            free(pBuffer);
            cbBuffer = cbBuffer * 2;
        }
    }while(s == STATUS_INFO_LENGTH_MISMATCH);

    PSYSTEM_HANDLE_INFORMATION_EX pInfo = (PSYSTEM_HANDLE_INFORMATION_EX)pBuffer;
    ULONG OldPID = 0;
    for(DWORD i = 0;i<pInfo->NumberOfHandles;i++)
    {
        if(OldPID != pInfo->Information[i].ProcessId)
        {
            OldPID = pInfo->Information[i].ProcessId;
            wprintf(L"PID: %d ",OldPID);
        }
    }
    free(pBuffer);
    FreeLibrary(hNtDll);
    getchar();
}

  原文中提到,在进行进程“隐藏”工作的时候,此处的句柄是一件容易被忽略的地方,因此需要注意隐藏由程序打开的相关句柄。由于系统中句柄数量经常变换,所以没有什么必要修改其中的 NumberOfHandles 域,因为如果修改此处的值,则需要不停对句柄的变化进行维护,开销比较大。在用户态下的进程枚举已经变得不可靠,因为一个内核级的 Rootkit 很容易就能够更改这些函数的返回结果。所以进程的可靠枚举应在内核态中实现,可以通过编写驱动来实现。

有关16位程序


  根据参考的第二篇文章:在 Windows 95,Windows 98 和 Windows ME 中,ToolHelp32 对待16位程序一视同仁,它们与 Win32 程序一样有自己的进程 IDs。但是在 Windows NT,Windows 2000 或 Windows XP 中情况并不是这样。在这些操作系统中,16位程序运行在所谓的 VDM 当中(也就是DOS机)。
  为了在 Windows NT,Windows 2000 和 Windows XP 中枚举16位程序,必须使用一个名为 VDMEnumTaskWOWEx 的函数。它的声明包含在 Windows  SDK 中的 VDMDBG.h 中,并且需要在项目中链接 VDMDBG.lib 文件。
  微软的网上帮助里面有一篇介绍的文章:如何在 Windows NT、 Windows 2000 和 Windows XP 上使用 VDMDBG 函数
0
Posted on 下午5:15:00 by Fan Zhang and filed under ,

  锁定屏幕的快捷方式是:Win + L,但是某些键盘没有 Windows 键,那如何方便的锁屏幕呢。

  一种方法是,打开开始菜单,选择注销,再选择切换用户。

  另外一种是,可以在运行中输入下面的命令,也可以建立一个批处理:

rundll32.exe user32.dll,LockWorkStation

0
Posted on 下午2:03:00 by Fan Zhang and filed under

  使用 GetText 来实现国际化是要依赖相应的语言文件的。其中 po(或者 pot)文件是原始的翻译文档。而 mo 文件是编译生成的二进制文件。在发布软件的时候,只要将 mo 文件存放在正确的位置,软件根据不同的 locale 设定寻找不同语言的 mo 文件,这样就能正确显示语言了。

  对于普通的软件使用者,如果对软件的翻译不满意,也可以手动修改翻译。这就需要反编译 mo 文件成 po 文件,修改 po 文件,再编译成 mo 文件。

  首先下载 GetText for Windows(还需要下载一个 libiconv,GetText 依赖 libiconv )。反编译 mo 文件成 po 文件:

msgunfmt.exe d:\test.mo -o d:\test.po

编译 po 文件为 mo 文件:

msgfmt.exe -o d:\test.mo d:\test.po

  po 文件用一般的文件编辑器就可以编辑,但是因为编码多为 unicode,所以记事本可能不行。还可以使用开源跨平台的 po 编辑器:Poedit

0
Posted on 下午1:47:00 by Fan Zhang and filed under

  安装完 SVN 后如果在命令行运行时出现乱码,则是因为中文编码没有正确配置。在 Windows 系统中,可以设置环境变量:

LANG = zh_CN.UTF8
APR_ICONV_PATH = svn安装目录\iconv
SVN_EDITOR = notepad.exe

  如果喜欢英文,也可以把 LANG 设置成 EN_US。至于 iconv 目录存放的是各种编码文件。

  还有一个问题,在使用 TortoiseSVN 的时候,可能会遇到这样的错误信息:"璁よ瘉澶辫触",这个明显是编码错误,转换一下就知道是"认证失败"。我 TSVN 的语言包看了下,这里翻译没有错误,看来是 TSVN 程序的一个 bug。

0
Posted on 下午8:07:00 by Fan Zhang and filed under

  今天,我在笔记本上的 Visual Studio 2008 TS 上编译一个正确的解决方案,发现在生成以后会自动关闭,但是项目已经正确生成。或者虽然不自动关闭,但是手动关闭时会报错。

  为了解决这个问题,我甚至还重装了一遍系统。最后终于确定,原来是和安全卫士360冲突...

  有些奇怪的是,我使用的另外几台机器安装的程序都一样,也是 VS2008 + 360,但都没有出现这个问题。

  顺便说下,Visual Studio 在第一次运行的时候可以看到它在进行一下初始化的配置。如何恢复默认设置呢?只要在 Visual Studio 的安装目录下找到 devenv.exe 文件,然后在命令行中输入:

devenv /ResetSettings

就可以恢复 IDE 的默认设置了。

0
Posted on 上午12:23:00 by Fan Zhang and filed under ,

  一般我们实现系统功能都是通过调用微软提供的公用 Win32 API 函数来实现。但今天我们采用的方法是通过本机系统服务(Native API)来探测本机系统信息。

  Native API 是 Windows 用户模式中为上层 Win32 API 提供接口的本机系统服务。微软没有为我们提供关于本机系统服务的文档 (Undocumented),也就是不会为对它的使用提供任何的保证,所以不提倡使用 Native API 来开发软件。

  不过由于通过 Native API 可以实现很多功能,所以相关的参考也可以找到很多。 比如 Gary Nebbett, Windows NT/2000 Native API Reference. New Riders Publishing, 2000. 是一本详细的参考书(@Amazon ),内容可能不是最新的,但非常有价值。 而 The Undocumented Functions 是一个内容充足的在线参考手册。

  为了探测系统信息,我们要使用一个函数:NtQuerySystemInformation(与ZwQuerySystemInformation相同,只是入口不同),这是一个属于 ntdll.dll 的函数。

  在 MSDN 上对这个函数定义如下:

NTSTATUS WINAPI NtQuerySystemInformation(
  __in       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  __inout    PVOID SystemInformation,
  __in       ULONG SystemInformationLength,
  __out_opt  PULONG ReturnLength
);

  难点在于各个数据结构是如何定义的。事实上,在不同版本的 Windows 中,这些数据结构的定义是有区别的,这也是微软不建议使用这些 API 的一个原因。

  通过我上面给出的资料倒是可以查到这些数据是如何定义的。比如 SYSTEM_INFORMATION_CLASS 是一个集合,如果我想要查看有关系统进程的信息,则要取 5 即 SystemProcessInformation。这个在 winternl.h 也有定义,但是这个头文件中的定义比较保守。更多的信息还需要自己 Google 才行。(比如上文提到的 The Undocumented Functions 中的 SYSTEM_PROCESS_INFORMATION

  对这个函数更详细的说明可以参见:NtQuerySystemInformation(ZwQuerySystemInformation)函数说明,这篇文章也有很全的 SYSTEM_INFORMATION_CLASS 是如何定义的。以及我最早参考的NtQuerySystemInformation,也讲了大部分数据结构如何定义。

  至于如果调用这个函数在分析完数据结构后就比较简单了。下面是一个简单的示例,里面还有很多没有说明的类型,不影响理解,进一步查看相关资料就能清楚了。

// 定义类型 
typedef NTSTATUS (WINAPI *PROCNTQSI)(UINT,PVOID,ULONG,PULONG); 
PROCNTQSI NtQuerySystemInformation;

// 调用 
NtQuerySystemInformation = (PROCNTQSI)GetProcAddress( 
GetModuleHandle("ntdll"), 
"NtQuerySystemInformation" 
);

  网上有很多例子可以参考,第一个是获取每个进程和线程:Processes and Threads Sample,讲解详细(网页上有一个小笔误),提供代码下载,用到了 Windows NT DDK,但是如果用上面我说的方法调用的话就不需要了 DDK 了。研究明白了这个,要点就全掌握了。

  还有一个是 Windows NT/2000系统中如何获取系统的启动时间,也有代码下载。

  上面提到的 GetProcAddress,GetModuleHandle,要涉及到动态链接库的使用。针对性的,可以参考:3个脱壳相关的重要函数介绍。简单地说就是:

  • 如果文件已经被映射进了调用进程的地址空间,则函数 GetModuleHandle 返回指定模块的句柄。注意,GetModuleHandle 是在不增加引用次数的情况下返回已映射模块的句柄。
  • LoadLibrary 把模块映射进调用进程的地址空间内。映射进地址空间后,如果必要,则增加模块的引用次数。最后用 FreeLibrary 把它从进程地址空间释放掉。
  • 使用 GetProcAddress 函数返回指定的输出动态链接库内的函数地址。
0
Posted on 下午3:58:00 by Fan Zhang and filed under

  最近遇到一个 Office PowerPoint 2007 的 bug,因为某些原因,一般是安装、删除输入法,导致在 PowerPoint 中无法输入中文,但是英文输入没有问题,也可以复制粘贴中文。

  网上给出的解决方案是开启高级文字服务:控制面板-区域与语言-语言-详细-高级-去掉"关闭高级文字服务"的勾。

  但是我用了也没有效果。最后重新安装了 Office 中的微软拼音输入法后问题解决。

1
Posted on 下午3:38:00 by Fan Zhang and filed under

  前面讲了用 Python 模拟浏览器进行登陆、抓取页面然后分析等操作。有的时候,我们还需要把筛选出的页面显示出来,最简单的方法自然是调用系统默认的浏览器。

  直接使用标准库中的 webbrowser 模块,看下面的例子:

import webbrowser 
webbrowser.open_new_tab('www.163.com')   
2
Posted on 下午7:01:00 by Fan Zhang and filed under

  之前说过使用 Python 登陆网站,我们已经可以获取任意一个网址的数据了。但是,在实际应用中,代理服务器往往是少不了的。

  在 urllib2 模块中,每一个 opener 可以用多个 handler 来增强功能,在前一篇,我们使用的是 Cookie 的支持,我们只要在这里再加上 proxy 支持就可以了。

#!/usr/bin/env python
# -*- coding: GB2312 -*-
# 

from urllib import urlencode
import cookielib, urllib2

# 准备cookie
cj = cookielib.LWPCookieJar()
cookie_support = urllib2.HTTPCookieProcessor(cj)

# 设置代理服务器
proxy_info = {  
        'host' : '127.0.0.1' ,
        'port' : 8118
}
proxy_support = urllib2 . ProxyHandler ( { 'http' : \
        'http://%(host)s:%(port)d' % proxy_info } ) 

# 构造opener
opener = urllib2.build_opener(cookie_support, proxy_support)
urllib2.install_opener(opener)

# 打开网页
page = urllib2.urlopen("http://www.163.com")
print page.read(1000)
page.close()
3
Posted on 下午7:17:00 by Fan Zhang and filed under

  据说,古今中外,不少伟大的雕塑和建筑,在问世之初都饱受非议,比如埃菲尔铁塔最初被认为是极其丑陋的庞然大物,现在已是法国的象征和巴黎第一地标。

  所以,对于我这个不懂艺术的人来说,看到一个狗屁不是的雕塑时,也不敢轻易发表意见。万一哪天这坨垃圾变成国宝了,我岂不是显得很不识货?

  因此,我绝对不说下面这两个立在北京大学光华管理学院新楼门前的两个玩意儿是垃圾。

guanghua_laozi.jpg

作者:田世信,名称:《刚柔之道--老子像》

guanghua_zhanli.jpg

作者:申红飙,名称:《蒙古人--站》

  不看作者的解释(见北大校园裸体雕塑与老子雕像相对),我是真不知道原来那个吐舌头的俏皮老头(或者说像个吊死鬼),是"源自孔子向老子请教何为刚柔之道,老子吐舌露牙、以唇齿比拟刚柔",还有那个光屁股遛鸟男是在展示"知识就是力量"。

  我不敢妄谈艺术,作者对这两个雕塑给出了合理的解释,为什么还有这么多人觉得不能接受呢?我想,这莫非是作者的功夫不到,不能表达出自己的思想?毕竟创作意图谁都会扯,但作品能否完美表现出来,就是艺术家该做的事情了。

17
Posted on 下午3:10:00 by Fan Zhang and filed under ,

  前几天,我的 Firefox 突然无法保存 Cookie 了,问题是:每次退出 Firefox 再进入,以前论坛的登陆信息都不存在了,需要重新登陆。

  我检查了各项设置(选项-隐私-Cookie),发现没有问题。我就没有理会,直到今天才得到解决方法:

  关闭 Firefox,把 Profiles 目录下的 cookies.sqlite 删除即可。

  分析原因,可能是某次非正常关闭,导致保存 Cookies 的数据库出错了。删除这个数据库,再次开启 Firefox 会重新建立一个,就正常了。

7
Posted on 下午10:38:00 by Fan Zhang and filed under

  对于大部分论坛,我们想要抓取其中的帖子分析,首先需要登录,否则无法查看。

  这是因为 HTTP 协议是一个无状态(Stateless)的协议,服务器如何知道当前请求连接的用户是否已经登录了呢?有两种方式:

  1. 在URI 中显式地使用 Session ID;
  2. 利用 Cookie,大概过程是登录一个网站后会在本地保留一个 Cookie,当继续浏览这个网站的时候,浏览器会把 Cookie 连同地址请求一起发送过去。

  Python 提供了相当丰富的模块,所以对于这种网络操作只要几句话就可以完成。我以登录 QZZN 论坛为例,事实上下面的程序几乎所有的 PHPWind 类型的论坛都是适用的。

# -*- coding: GB2312 -*-

from urllib import urlencode
import cookielib, urllib2

# cookie
cj = cookielib.LWPCookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
urllib2.install_opener(opener)

# Login
user_data = {'pwuser': '你的用户名',
             'pwpwd': '你的密码',
             'step':'2'
            }
url_data = urlencode(user_data)
login_r = opener.open("http://bbs.qzzn.com/login.php", url_data)

  一些注释:

  1. urllib2 显然是比 urllib 高级一点的模块,里面包括了如何使用 Cookies。
  2. 在 urllib2 中,每个客户端可以用一个 opener 来抽象,每个 opener 又可以增加多个 handler 来增强其功能。
  3. 在构造 opener 时指定了 HTTPCookieProcessor 做为 handler,因此这个 handler 支持 Cookie。
  4. 使用 isntall_opener 后,调用 urlopen 时会使用这个 opener。
  5. 如果不需要保存 Cookie,cj 这个参数可以省略。
  6. user_data 存放的就是登录所需要的信息,在登录论坛的时候把这个信息传递过去就行了。
  7. urlencode 功能是把字典 user_data 编码成"?pwuser=username&pwpwd=password"的形式,这样做是为了使程序易读一些。

  最后一个问题是,pwuser、pwpwd 这类的名字是从哪儿来的,这就要分析需要登录的网页了。我们知道,一般的登录界面都是一个表单,节选如下:

<form action="login.php?" method="post" name="login" onSubmit="this.submit.disabled = true;">
<input type="hidden" value="" name="forward" />
<input type="hidden" value="http://bbs.qzzn.com/index.php" name="jumpurl" />
<input type="hidden" value="2" name="step" />
...
<td width="20%" onclick="document.login.pwuser.focus();"><input type="radio" name="lgt" value="0" checked />用户名 <input type="radio" name="lgt" value="1" />UID</td>
<td><input class="input" type="text" maxLength="20" name="pwuser" size="40" tabindex="1" /> <a href="reg1ster.php">马上注册</a></td>
<td>密 码</td>
<td><input class="input" type="password" maxLength="20" name="pwpwd" size="40" tabindex="2" /> <a href="sendpwd.php" target="_blank">找回密码</a></td>
...
</form>

  从这里可以看出,我们需要输入的用户名密码对应的就是 pwuser 和 pwpwd,而 step 对应的则是登录(这个是尝试出来的)。

  注意到,这个论坛表单采用的是 post 方式,如果是 get 方式则本文的方法就需要变动一下,不能直接 open,而是应该首先 Request,然后再 open。更详细的请看手册...

  有一篇文章供参考:解决在 Python 中登录网站的问题

2009-03-09Up:在 Python 3 下可以参考:Python 3.0 中的编码和字符串

1
Posted on 下午11:18:00 by Fan Zhang and filed under

  今天去看了"2008年中国国际信息通信展览会"(P&T/EXPO COMM CHINA 2008),在顺义那个新的国际展览中心。太远了,坐车都得一个多小时。听说附近有豪华别墅区,王菲就住在这穷乡僻壤里。

  比起以前参加的展会来说,人不算很多,我觉得还是太偏僻的缘故。虽然有所谓的摆渡车,但也就是那么几辆大巴。

  展会上没有见到什么出彩的东西,或许是因为拿出来展示的都是较为成熟的技术吧。

  不多说了,因为大部分看我 Blog 的人对通讯这口没啥兴趣。其实我也是...最后,放一张图,请放心,不是什么电子元器件...

OKWAP 展台(点击查看)

  btw,<div style="TEXT-ALIGN: center"> 不能在 Firefox 下令表格居中?在 IE 下倒是没有问题。

8
Posted on 下午4:40:00 by Fan Zhang and filed under

  本来不想写的,因为微软打击盗版已经不是一天两天了,这次使用的手段也不新鲜。关键的是,由此涌现出无数[文明用语],让我很震惊。

  首先是抵制的。这种人太无耻,用了盗版还理直气壮。有一个新闻是:中国网民向微软递交抗议信。微软打击的就是这帮人,本身就没给微软带来利益,难道还要讨好你不成?

  其次是上告的。比如:微软黑屏行动是有计划的大规模网络犯罪律师向公安部举报微软黑屏涉嫌黑客攻击犯罪。尤其是这个律师,简直没文化啊,有人还专门写文章从技术角度对其批驳,太给他面子了。

  还有让中国自己做操作系统的。他们说,中国要自强,自己做系统,把微软赶回老家。参见:金山抵制微软黑屏评论精选。暂且不说中国自己开发一个操作系统的可能性及其付出的代价。我就问这种人一句:中国真出了操作系统, 你会掏钱买吗?如果真的有人辛辛苦苦做出一个操作系统,不是国家买单,就是全都饿死。

  有人觉得,微软定价太贵,一个操作系统就要成百上千。我却觉得,从软件开发的角度来讲,如果真像某些人希望的那样,一个 Windows 只要50元,那微软还是别开发了,连员工的工资都不够,更别说赚钱了。我承认,2000元一套系统的价钱很多人承受不起,但是没有操作系统,2万元的机器也只能当摆设。

  有人不明白,为什么微软会提示:"您是盗版软件受害者",他们会觉得,我明明是盗版软件的受益者啊。说好听点,这种人是目光短浅,说难听点,就是偷了别人钱还在疑惑:明明能偷钱,干嘛还有人要辛辛苦苦工作。

0
Posted on 下午7:59:00 by Fan Zhang and filed under

  前几天在折腾那几块硬盘的时候,突发发现其中一块读写速度骤降,从原先的 80MB/s 降到了 8.5MB/s。使用磁盘检查、更换数据线、去掉其他硬盘都没有解决问题。

  后来发现原来是传输模式变成了PIO,在设备管理器,SCSI 和 RAID 控制器下面,改回 DMA 5 就恢复了。

  分析故障出现的原因,可能是有一次硬盘线没有插好,导致 Windows XP 为了保护硬盘而关闭 DMA 模式,只使用兼容模式。

2
Posted on 下午11:10:00 by Fan Zhang and filed under

  经人介绍,在凤凰网上看到了两则新闻,很有趣...

2008年09月28日:

  温家宝:在凤凰电视上看到曼德尔森喝中国牛奶很感动

2008年10月08日:

  英商务大臣曼德尔森上任当天 肾结石发作接受手术

3
Posted on 下午8:46:00 by Fan Zhang and filed under

  硬盘越来越便宜了...几年前我还使用刻录 CD 保存数据,但是现在感觉用 DVD 刻录也不如再买块硬盘方便。下图来自 it168。

  我的经验来看,刻录光盘首先受到容量限制,不能很好地组织数据;刻录花费大量的时间;刻完的盘还会自然损坏,根本不可能像所说的那样放上30年。

  这款希捷 ST31000340AS 1T 硬盘已经不到900元,我觉得比用光盘划算多了。

  不是专业评测,我也不怎么关心硬盘速度,实际使用中两块硬盘拷贝速度约为 35MB/s(其中一块是 IDE 希捷160G),还算满意。

  找些毛病:

  • 或许是电机声音大,很高频的噪音,我室友听不到,我倒是听的清楚。(这点也可能是我误会,但反正我装上它就能听见,拔下就听不到)
  • 做工没有几年前的那么细致了...但还是不错,反向封装设计,看不到元器件。
0
Posted on 下午8:42:00 by Fan Zhang and filed under

  叛逆的鲁路修经过两部折腾终于完结了。虽然第二部剧情进展略逊色于第一部,吐便当的也是一个接一个,但大结局还是相当精彩、值得回味的。

  回顾整个剧情,有的人早就死了,比如尤菲米娅;有的人肯定要死,最后的确死了,比如罗洛;有的人总是要死,最后也没死成,比如藤堂;有的人早该死了,最后也不知死没死,比如黎星刻。

code_geass_25_all.jpg

  这张全家福里面就没有黎星刻的影子,莫非在照相?还有下面一张,画面正中神虎倒是站着,里面不知坐的是不是黎大叔。

code_geass_25_meet.jpg

  据我分析,编剧一开始是想让他死的,不然他就文武双全、盖世无双了。配角怎么能比主角强呢,所以给他安了一个绝症,天天吐血,随时准备领盒饭。不过,随着剧情的发展,观众们都不想(我推测...)让萝莉天子早早守寡,于是就没法死了。但是,不死又没法解释前面设下的伏笔,于是就这样隐晦的表示了。按照惯例 ,这个家伙肯定没死,在后面偷着乐呢。

  为了确认这个家伙死没死,我还又看了一遍...发现了这张图。说明至少这个时候还活着。

code_geass_25_li.jpg

  好了,不说他了,谈谈鲁路修。这更不用说了,肯定死不了。有人问,他被捅了个透心凉,还大出血,咋会没死呢?答案很简单,因为他有 Code 啊。至于所谓的 Code 是不是只有在被杀死一次后才能显现,我就不分析了。(那些说是咲世子在里面掺和的被我无视了。)反正,最后他和 C.C 去乡下拉马车了。

code_geass_25_lulucc.jpg

  有人说娜娜莉获得了能力:最后鲁路修被刺跌落到娜娜莉身边,娜娜莉摸到鲁路修的时候看到鲁路修的历史(或记忆)。不过我觉得这是被施与了 Geass 的典型症状。

  其他角色们一个个都过得挺滋润,卡莲上学去了,聒噪男玉成开了间酒馆,扇把人家的肚子搞大了,最搞笑的竟然是 Orange 真去种橘子了,还是和阿妮娅一起。

code_geass_25_orange.jpg

  嗯,以上内容涉及到分析的都是我扯的,到底谁死谁活还是编剧说了算。

2
Posted on 下午3:39:00 by Fan Zhang and filed under ,

  今天发现在百度搜索"晓月",竟然能排在第一个,原来的什么家具城、娱乐场所都跑到第二页去了。

  莫非是百度因为奶粉问题,想要低调处理竞价排名?

  btw,我的 Blog 应该采用的是 UTF-8 编码,所以如果直接嵌入百度的搜索结果为:

http://www.baidu.com/s?wd=晓月

就会出现乱码。所以需要加上编码:

http://www.baidu.com/s?ie=utf-8&wd=晓月

3
Posted on 上午1:00:00 by Fan Zhang and filed under ,

2008-09-27Up:

  发现一点小问题,我把PageRank的小图标拖到了工具条外,然后把工具条隐藏,发现它就不起作用了。只有当我显示工具条的时候,PageRank 才会正确显示,否则就会提示没有 PageRank 信息。

  Google Toolbar for Firefox 终于正经更新了一下(下载)。在没有工具条的日子里,我最常用的功能 Google Bookmarks 是用 GMarks 替代,网页历史使用 GM 脚本替代

  我的布局采用替代 Firefox 默认搜索框,这样可以通过下拉表单选择最近的搜索。有很多搜索选项:Google 搜索,站内搜索、网页历史搜索、Gmail搜索等等。我希望能添加百度搜素,方法很简单,只要在百度网页的搜索框上点右键,在菜单中选择"生成自定义搜素",就可以生成百度搜素的按钮了。我记得在上一个版本还需要使用高级编辑功能修改网页编码,现在直接添加就可以了。

  GMarks 虽然也可以使用 Google 书签,但是在添加一个书签的时候很不方便,而 Google Toolbar 自带的书签按钮点起来就非常舒适。

  同时 Google Toolbar 整合了 Google Notebook,原来的 Google Notebook 扩展被直接替换,连删除都省了。

  还有一个同步工具栏的功能,挺好的,我记得以前自定义按钮都是存放在本地硬盘的用户文件夹下,为制作便携版造成了很大的不便。

  新增加了表单填充功能,不太实用。

  值得一提的是,新版本的按钮功能似乎可以非常高级,比如添加 Google Talk 到一个按钮上。

3
Posted on 下午10:48:00 by Fan Zhang and filed under ,

  据说来自新加坡。

fuhou1.jpgfuhou2.jpg

2
Posted on 下午7:57:00 by Fan Zhang and filed under

  几天前我发现 Picasa 相册的标签似乎出了点问题,在所有标签的列表处,会出现一个"空白标签"。

picasa_bug_1.png

  如图,标签 nici 上面的那个标签,显示有3张照片,但是点击会出现错误信息:

picasa_bug_2.png

  这个问题是在删除一个标签的情况下出现。比如我删除某一个照片上的标签,则空白标签会增加一个。

  在 Picasa Help Group 已经有了这个 bug 的报告,不知道什么时候能够解决。

0
Posted on 下午7:15:00 by Fan Zhang and filed under

  去买咖啡,所有的咖啡中的牛奶都换成了豆奶。唯一不需要牛奶的是美式咖啡,不好喝...

6
Posted on 下午10:12:00 by Fan Zhang and filed under

   我们经常有这种需求:

  • 在不同的地点,不同的计算机上编辑同一份文档
  • 希望可以随时随地访问自己的文件(比如照片),并能分享给家人
  • 把自己的重要文件备份起来

  如果你不想带着U盘到处跑,觉得把文件保存在自己的邮箱里面很麻烦,你可以试试 Dropbox。不同于一般的网络硬盘服务,它不仅可以通过网页上传、管理文件,还提供一个跨平台的客户端。通过这个客户端,用户可以操作本地一个文件夹来管理远程的文件,任何操作都会被自动同步。不仅如此,Dropbox 还提供版本控制功能,完全不同担心文件误修改或者误删除。

  Dropbox 现在免费提供了 2G 的空间,保存文档和图片应该足够了。下面详细介绍下客户端的使用。

  首先下载 Dropbox 的客户端(链接如果失效,可访问主页下载),安装客户端后注册帐户。

Dropbox_01.png

  使用自己的邮箱注册以后,可以看到一个简单的使用介绍。

Dropbox_02.png

  在教程最后,有一个选项,问是否指定 Dropbox 存放的文件夹,我选择了指定(默认是我的文档下面的 My Dropbox)。

Dropbox_03.png

  我指定的保存位置是桌面。注意,不需要手动再新建文件夹了,直接选择桌面会自动建立一个 My Dropbox 的文件夹。这个文件夹的位置在软件的设置中也是可以更改的。

  打开 My Dropbox,你会看到一些文件夹和文件,这些都是新建帐户的演示文件,可以删除。

Dropbox_04.png

  注意到,文件的图标左下角有一个绿色的小图标,表明的是已经同步的文件。我简单的试验了一下版本控制功能,对冲突的文件也能很好的识别,它会给出所有冲突文件的不同副本。个人使用的时候不必担心版本冲突的问题。

  Dropbox 预设了两个文件夹 Photos 和 Public,这两个文件夹有特殊性。

  • Photos 文件夹使用网络浏览器访问的时候,提供了 Gallery view,在使用网页上可以方便查看照片。
    Dropbox_05.png
  • Public 文件夹提供外部链接的功能,可以直接让任何人访问这个文件夹中的某个文件。在文件上点右键,从菜单中可以选择"Copy public link" ,把这个链接直接发送给朋友,他就能查看、下载这个文件了。
    Dropbox_06.png

  文件夹还有分享功能,可以和朋友共同分享一个文件夹(能否通过这个方法获取更大的空间?自己建立一个新帐户,然后分享新帐户的文件夹...)。登陆网页,还可以看到能把一个文件夹打包下载的选项。

  2008-09-15Up:建立多帐户获取更大的容量目前是行不通的,分享的文件夹会占用所有帐户的资源。这是制作方避免取巧获得容量的手段,但显然不是一个好的解决方法。我觉得应该把共享文件夹分成两种:一种是目前的分享,共享的任何人可以进行修改;另一种是只读,被分享者只能查看下载。

  以上我对 Dropbox 做了简单的介绍,这个软件/服务使用起来非常简单和流畅,同步工作都在后台进行,完全感觉不到迟缓。我觉得这才是我想要的网络硬盘服务,本来等着 Google 推出呢,看样子是 Google 不喜欢桌面客户端,而想把所有的功能通过浏览器来实现。在我梦想中,我去任何地方都可以不带我的计算机,在任何终端登陆我的帐户都可以查看、编辑、分享我的文件。如果我的桌面终端有强大的编辑器,我可以方便的和网络上的文件同步,比如 Dropbox 的方式。如果没有编辑器,我也可以通过浏览器来编辑我的文件,比如 Google Docs。

4
Posted on 下午9:15:00 by Fan Zhang and filed under , , ,

  今天入手了一个 SanDisk 的 U3 盘,使用了一下,感觉还不错。

  目前只有黑色的,都是塑料外壳,伸缩式的 USB 连接器。自带 U3 技术。推拉口的地方是指示灯,非常漂亮。

  插入U盘后,会出现两个驱动器,其中一个是 CDFS 格式,只读,存放的是系统文件。另外一个是 FAT32 格式,就是和普通U盘一样的存储区域。如果允许自动运行,则会开启 U3 的 LaunchPad。利用 LaunchPad 附带的安全保护功能,可以给数据分区加密。只有当输入了正确的密码后才能访问数据。读写速度都不错,我也没有专门测试,简单用了一下,写大文件能达到 8M/s 。

  我最关心的还是如何量产的问题。因为 U3 盘已经是一个 CDFS 分区,一个数据区,所以肯定可以量产,只需要选择合适的工具。

  在上面提到的官方网站可以下载 U3 LaunchPad 的安装程序和移除工具。所以不用担心量产失败,随时可以用这两个工具重新恢复原始设置。另外,在运行 U3 LaunchPad 的时候需要从网络下载 U3 的原版启动镜像:cruzer-autorun.iso(直接下载),在 LaunchPad.zip 里面可以找到 u3dapi10.dll(下面会用到这个文件)。

  从 U3 Community 可以下载到 Universal Customizer 1.0.0.8页面),使用它就可以使用自己的 ISO 文件重新格式化制作了。

  如果U盘是 8G 的,那么下载到的 Universal_Customizer 中 u3dapi10.dll 的版本就太低了(1.0.1.0),可能会把 8G 格式化成 4G 的,使用上面提到的同名文件替换(我使用的是 1.0.9.0)可以解决这个问题。

0
Posted on 下午8:11:00 by Fan Zhang and filed under , ,

  一台 HP 的笔记本,突然无法连接到网络,前一天正常关机。

  在连接属性里面可以看到,没有分配到 IP,显示的地址是 169.254.*.*。在设备管理器里面有关网络适配器的部分,似乎有一些硬件没有安装好。

  尝试了以下方法,都没有成功:

  折腾了几个小时,故障依旧,心中升起了很强的挫败感...于是重装系统,恢复正常...

4
Posted on 下午12:13:00 by Fan Zhang and filed under ,

  使用 BlackBerry 访问 m.google.com 可以下载到最新发布的 Google Mobile App for BlackBerry,通过它可以更方便地使用 Google 的为手机提供的多项功能:搜索,邮件,地图等等。

  因为是月初,流量还有剩余,亲自当小白鼠下载试验。

  我下载的 Google Mobile App 版本是 3.1.131,大小 383.8KB。下载完毕后,需要设置应用程序权限,不用重启即可使用。

  嗯...经过使用,发现这个程序只是一个外壳,它要调用相应的其他程序才完成操作。比如搜索,在点击 Search 后调用浏览器。选择 Gmail图标 调用的是 Gmail,如果没有安装 Gmail,则那个图标是灰色的。

  比较失望,我本来以为它把所有应用整合到了一个程序里面,谁想只是一个"快捷方式"大集合。


  还有,最初 Gmail 2.0.5 在我 BlackBerry 8700 ROM 4.5 下面始终无法运行,问题为:

  始终停滞在"Loading...Please be patient while loading for the first time...",等几分钟之后,就会出现红色的 net.rim.device.api.io.IOCancelledexception。

  今天我又重新从网站下载(按照下面的方法),第一次运行,我放了一个小时没管,仍然是停留在上面的地方。但是这回我退出再进入就正常了。

  如果程序安装有问题,可以参考小众上的 Gmail 手机版更新至 2.0.5 及安装教程

  中国移动给我们出了难题,它肆意抹去了手机发送出去的 agent 信息,以至于手机访问http://gmail.com/app 时无法让 Google 得到我们的手机型号,就不能针对性的选择 Gmail 版本。所以,很多同学无法正常安装。

  解决思路:用浏览器伪装 agent 信息,从而得到真实下载地址,再通过手机访问,即可安装成功。

  解决办法:在 Mobile Browser ID (User-Agent) Strings 得到手机的 Agent 信息,通过 Firefox 的扩展 User Agent Switcher 把 firefox 伪装成你的手机,用手机自带浏览器访问 http://gmail.com/app 得到 Gmail 手机版程序网址。

  我使用的 Agent 是:BlackBerry8700r/4.5.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/105,获取的下载地址是:http://mail.google.com/app/v2.0.5/L1/BlackBerry-42/GoogleMail.jad?source=mobileproducts

2
Posted on 下午3:45:00 by Fan Zhang and filed under ,

  我编写了一个 Windows Mobile 下的 Directshow Filter,但是如何注册却成了问题。在 Windows 下面只要使用 Regsvr32 即可,但是这个程序在 Windows Mobile 的模拟器中不存在。

  首先参考 MSDN:Registering DirectShow FiltersCreating a DLL in DirectShow

  为了偷懒,我决定使用 eMbedded Visual C++ 4.0(下载)附带的 RegsvrCE.exe 来注册 DLL。把 regsvrce.exe 和 dllname.dll 一起复制到模拟器中,设法运行(比如编一个小程序)"regsvrce.exe dllname.dll"即可。

  中间我还遇到了一个小问题,当我注册一个 Filter 的时候,返回错误:

Loadlibrary("dllname.dll") failed. GetLastError returns 7e.

  错误代码 7e 的含义是没有找到特定的模块,应该是这个 DLL 调用了当前系统中不存在的 DLL。经过检查发现是我在编译 Filter 的时候,运行时库选择了"多线程 DLL(/MD)",而它所需要的 msvcr90.dll 在模拟器中似乎不存在。于是我从 Visual Studio 目录下面的把相应的 msvcr90.dll 复制到模拟器然后注册,就可以注册我的 Filter 了。如果不想复制这个文件,把运行时库改为"多线程(/MT)"也可以。

  如何在程序中使用"RegsvrCE.exe",下面有一个例子:


SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = _T("regsvrce.exe");
ShExecInfo.lpParameters = _T("Program Files\\H264VideoDecoder\\H264VideoDecoder.ax");
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);

  其实还有一个好的方法,就是在路其明的《DirectShow 开发指南》第10页介绍的方法。在应用程序中使用 LoadLibrary 装载这个 Filter 文件,找到它的导出函数 DllRegisterServer(或 DllUnregisterServer)的入口地址,然后执行它即可。不过书中的参考代码有些错误,就是在 typedef 的时候,下面是修改后的代码:


BOOL RegisterFilter(LPCWSTR inFilterAx)   
{   
    typedef HRESULT (WINAPI * REGISTER_FUNC) (void);   
    REGISTER_FUNC   MyFunc = NULL;   
   
    HMODULE hModule = ::LoadLibrary(inFilterAx);   
    if (hModule)   
    {   
        MyFunc = (REGISTER_FUNC) GetProcAddress(hModule, _T("DllRegisterServer"));   
        BOOL pass = (MyFunc != NULL);   
        if (pass)   
        {   
            MyFunc();  
        }   
        ::FreeLibrary(hModule);   
        return pass;   
    }   
    
    return FALSE;   
}  

  使用的时候,只需要调用:


RegisterFilter(_T("Storage Card\\H264VideoDecoder.ax"));
4
Posted on 下午10:09:00 by Fan Zhang and filed under

  昨天一个朋友给我打电话,说使用 Ghost 恢复系统的时候把除了C盘以外的其他分区都弄没了。他只想恢复出倒数第二个分区中的照片。折腾了几个小时,算是有惊无险地恢复成功,总结下经验。

  我事后分析的问题原因是:恢复系统时,Ghost 文件本身就在 C 盘,在恢复的时候,有一个警告,提供三种选择:保留,删除 ,中断操作。当时的选择是保留,恢复后其他分区就找不到了。(Ghost 版本 8.3)

  解决:在 U 盘使用 R-Studio,一款非常不错的数据恢复软件,不过不是免费的。具体操作很简单,只要扫描硬盘(我选择的模式是 simple),然后就会找出相应的分区(有可能某个分区被分隔成了几个片段)。打开找到的分区就能看到可以恢复的文件。找到照片文件夹,选择恢复到移动硬盘,很快就把所有的文件都恢复了。在恢复的过程中,提示有重名文件,我选择了重命名,最后我发现重复的文件中有一个是原始文件,另外一个是 0 字节,我就把所有重命名的文件都删除了。

  体会:我家父母用的台式机备份也是 Ghost,不过我将操作简化到只用插入光盘,然后回车就行的程度。因为即使是一键恢复,也会因为多种参数的选择给他们造成困扰 :),不过这种缺乏定制性的方式显然就只能自家用了。

2
Posted on 下午12:13:00 by Fan Zhang and filed under

  今天 Picasa 推出了脸部识别的功能,试用了一下,觉得十分激动。

  登陆 Picasa 相册就会提示有这一项功能,选择了试用以后,经过几分钟的索引,就会从所有照片中识别提取头像。头像会自动聚类,我可以方便的加入姓名标签,姓名也可以和 Google 的联系人绑定。

  操作起来非常简单流畅,识别准确率很高!

0
Posted on 上午11:15:00 by Fan Zhang and filed under

  Google Chrome 是 Google 开发的网页浏览工具,今天试用了一下。说实在的,从现在的表现来看,我无意从 Firefox 转移阵地。但是如果作为移动设备上的浏览器,我觉得这种设计非常合适。

  网上已经有很多详细的评测了,下面只是几点体会。

  优点:

  1. 有一个"创建应用程序快捷方式"可以给网页服务创建一个桌面快捷方式。
  2. 界面设计简洁美观。
  3. 标签功能很强。

  缺点:

  1. 安装过程非常不绿色。
  2. 网银什么的别想了。
  3. 没看到扩展。

  我很不负责任的草草感受了一下就删除了...作为一款开源软件,又有 Google 撑腰,期待之后的发展。

3
Posted on 下午11:40:00 by Fan Zhang and filed under , , ,

  在 cnBeta 上看到这组该死的视频后,我就觉得有种不发表下评论不痛快的感觉。

  不知道这组有关瑞星的视频是不是官方做的,如果是,那太侮辱观看者智商了,而且很黄很暴力。如果不是官方制作,而是瑞星支持者的作品,我只能感慨...

  如果读者中也有用瑞星的,请听我的劝,不要用了,尤其是那些本身就用盗版的,赶紧换一个吧...

  为了平复看到如此弱智视频的情绪,下面还有一个有趣的。(下面的视频与上文无关)

2
Posted on 下午4:54:00 by Fan Zhang and filed under

  我有一个程序需要在 Windows Mobile 上运行,一直使用的是 Windows Mobile 6 SDK 自带的模拟器来调试和测试。我有两个台式机,其中一台 CPU 是 AMD Athlon 3000+,另一台是 Intel Core2 2.33GHz。模拟器在这两台机器上运行的效率差别很大。这可能是因为我第一台 PC 本身就很慢。

  注意到在模拟器中查看 CPU,显示的是 ARM Intel 376Mhz。我以为当我的 PC 足够快的时候,程序在模拟器上运行的速度就等同于在同等真机上的速度。

  不过,今天我找了一个多普达的机器,CPU 是 Samsung SC32442 400Mhz,但是运行速度比我第二台 PC 的模拟器要慢 20%,差别很大。

  难道模拟器的 CPU 主频只是摆设,具体速度是由 PC 本身的 CPU 决定的?

5
Posted on 下午11:14:00 by Fan Zhang and filed under

  今天在 IT 八卦站 cnBeta 上看到一则消息,经确认属实:联想解答用户关于 NVIDIA 显卡 GPU 的问题

  NVIDIA公开的G84和G86系列笔记本显卡GPU问题主要与机器内部核心温度变化有关。联想笔记本产品具备良好的散热设计,经严格测试,Idle(空闲)状态的GPU温度远低于NVIDIA提供的危险温度69摄氏度。因此联想产品基本不受此问题影响,请您放心使用。

  别的厂商都承认有问题,比如 DELL 还发布了一个 BIOS 升级补丁,虽然是杯水车薪,但至少正面面对问题。

  你联想怎么这么牛啊,显卡质量问题一带而过(虽然不是你制造的),就开始吹嘘自己良好的散热设计了。最可笑的是"严格测试"了"空闲状态"下温度不高,废话,我不开机温度更低!

  而且问题不是出在高温上,温度的变化起伏更容易导致故障出现。

  联想的这个声明简直没过大脑,短短两句话就想把人打发。就算机器不会出现问题,这个声明也只能体现出与其知名企业不相称的劣质的公关水平!

3
Posted on 下午10:59:00 by Fan Zhang and filed under

  周六那天晚上,月光皎洁,我走在回宿舍的路上。

  月亮在云上散发着柔和而明亮的光芒,云彩随着风缓缓飘动,很久没有见到这样的景色了。

  快走到宿舍的时候,忽然看到前方天空凭空出现一股升腾的雾气,大概离地十米,高度约有三米。云雾还隐约散发出光芒。我当时就被吸引到了,还在猜测或许是某处探照灯灯光照射的结果。

  但是随着我走近,发现不是灯光,因为它是垂直向上翻腾,而且聚集在面积大概一平方米的区域。奇怪的是,雾气下面什么也没有,突然出现的样子就像是天空有一层透明的挡板。

  我快步走到近处想仔细观察,那股雾气像失去了支撑突然"落下",如同轻纱坠地,随即消失不见。

  我没想试图给它一个解释,就权当一个神奇的经历吧~

12
Posted on 下午11:24:00 by Fan Zhang and filed under

2008-12-17Up:

  此问题已修正。

  我在 Blogger 中设置了把评论发送到 Gmail,以便能即时看到并回复评论。可是从今天开始发送来的邮件标题都是乱码,比如:

[&#26195;&#26376;] 对下列文章的最新评论 &#36890;&#36807;&#20195;&#29702;&#20351;&#29992;Zoundry Raven&#21521;Blogger&#21457;&#24067;&#25991;&#31456;.

  虽然我知道这是十进制表示的 Unicode 码,说明 Google 在向全面 Unicode 转变,是个好事情。不过也别这样显示啊...希望能尽快修正这个问题。

  附:E-mail乱码解码器

2
Posted on 下午11:34:00 by Fan Zhang and filed under ,

2008-08-18Up:

  哦,我错怪了有关部门,不是之前传闻的乱拔网线,而是"封的就是你"...

  CSDN关于恢复网站服务的公告:由于某个新注册网友在Blog中发表了多篇P2P方式的奥运直播,我们未及时清理违规内容,CSDN网站被停止服务了10天,对此给各位网友带来的不便,我们深表歉意。为了后续更好地为各位网友服务,请各位网友不要发表含有奥运版权的视频和相关信息。

  这几天我就发现 CSDN 即使用了代理也上不去,在月光博客上看到专业性技术网站CSDN被关闭才知道是有网站盗播奥运视频,机房遭封锁,csdn.net受牵连

  CSDN 在国内的影响力自不用说,这次被关对我也造成了不小的困扰。

  这些个部门凭什么这么粗暴?难道邻居犯罪,我也得挨枪?这简直没天理。这种事,说好听点就是一点都不和谐,说不好听就是蛮横粗暴、滥杀无辜,放在旧社会,这不是草菅人命吗?

  有那么多技术手段可以采用,别为了方便就直接拔网线。要是不会,也多学习学习!

  我也不指望有人能出来道歉,承认错误,赶紧把 CSDN 恢复了我就"知足常乐"了!

0
Posted on 上午10:22:00 by Fan Zhang and filed under

  从原来的 DirectX Summer 2004 换到 Windows SDK 以后,发现在 GraphEdit 中在 Filter 上点右键不能查看属性了。

  需要将 SDK 中的 proppage.dll 文件注册一下:regsvr32 ...\proppage.dll

7
Posted on 上午5:41:00 by Fan Zhang and filed under ,

  太热,换一个模板。

  从写写改改那里看到了这个 Wordpress Admin 模板,今天终于下决心换,改了好久,好多以前的技巧我都忘了。

  正好 Google Pages 也要倒了,图片什么的也换一个空间。Favicon 直接用 Base64 编码了,因为找不到可以存放 ico 的相册。

  另外,谁能告诉我 Google Sites 上传的附件为什么不能直接下载,但是去掉链接最后的 "?attredirects=0" 就可以下载。

3
Posted on 下午11:39:00 by Fan Zhang and filed under

  受到新主题的诱惑,把我的黑莓 8700 升级到了 4.5。一开始选择的版本比较低,结果中文很多都显示不出,都是些小方块。最后安装了东亚版的 4.5.0.52 解决了这个问题。

  注,所谓的 4.5.0.75 这个是运营商打包封装的版本号,应用程序的版本号是 4.5.0.52。下载需要用代理。

中文支持

  这个版本已经能够很好显示中文,可惜的是 8700 的版本仍然没有拼音输入法。不过有五笔划输入法,现在正在刻苦学习中。数字 12345 对应横竖撇捺折,头晕啊...

界面

  当初升级就是看上了新版本的主题,使用了一下,发现界面细节变化很多,漂亮了很多。自然,我感觉速度也慢了一点。主题的图标有很多效果,而且菜单也可以半透明。

Document to Go

  在黑莓上处理 Office 文件,有兴趣的可以看:黑莓专用Document to Go Premium安装包放出

问题

  我之前提到的一个 Bug:重新启动后,自动背光功能设置无效,必须重新设置。这个问题似乎没有解决。

  对于耗电量,我的经验是和开启的程序有关,比如看电子书的 AnyView,只要打开,电量就刷刷的掉。所以升级到 4.5 以后电池消耗的快我想也是正常,毕竟程序复杂了。但是,还没有 AnyView 那么夸张。

0
Posted on 上午12:48:00 by Fan Zhang and filed under ,

  今天重新配置了 Visual Studio 2008 + Windows SDK 6.1,编译 BaseClasses 很轻松通过。但是在编译之前写的一个程序的时候却提示:

...\directshow\baseclasses\refclock.h(80) :
                        error C2061: 语法错误 : 标识符"CAMSchedule"      
...\directshow\baseclasses\refclock.h(139) : 
                        error C2143: 语法错误 : 缺少";"(在"*"的前面)   

之类的错误。

  问题出在 refclock.h 引用的 Schedule.h 文件在 Include 和 BaseClasses 重复出现了,而且内容不一致。所以需要在引用路径的时候把 BaseClasses 的路径提前。

3
Posted on 下午10:54:00 by Fan Zhang and filed under

  如果不是因为有事,我才不愿意在北京待着。

  今天上公交竟然查我的包,虽然我的包里只装了一卷卫生纸。

  而且,笔记本电脑也不准带上公交,826、690 已证实,说是"上面通知"。已经刷卡的会被直接退现金。听说 328 好点,会和蔼地提醒你把电池卸下来单独放,防止爆炸。

  我想知道,要真是什么危险品,售票员认得出来吗?

1
Posted on 下午2:34:00 by Fan Zhang and filed under

  这个问题已经有好多文章讨论,我再写一遍只是想表达一下我对微软的不满...

  问题描述:安装 Visual Studio 2008 进行到 Visual Studio Web 创作组件 (Visual Studio Authoring Component) 时提示安装失败。

  问题原因:这个组件安装需要使用 Office 2007 的安装文件,如果当时 Office 安装完毕后把 MSOCache 文件夹删除就会出现这个问题。事实上,所需的文件 Visual Studio 自己也有,只不过因为先装了 Office,安装程序就只能找 Office 相应的文件(依靠签名识别)。

  解决方法:重新找到 Office 安装光盘,修复下 Office(这时候 MSOCache 就回来了), 重新安装 Visual Studio 即可。

0
Posted on 下午10:51:00 by Fan Zhang and filed under ,

  我在使用 TortoiseSVN 管理个人文档代码中介绍了开源的版本控制软件 Subversion。对个人用户来说使用 TortoiseSVN 就足够了,但对团队开发来说,需要一台服务器保存版本库,以便开发人员访问,所以需要安装 Subversion(不过 TortoiseSVN 仍然可以安装,不冲突)。另外,还需要一个缺陷跟踪系统来管理 Bug,我选择了 Trac。当然,Trac 并不是唯一的选择,能与 SVN 集成的缺陷跟踪系统也有不少,而且 Trac 的 Bug 管理功能有待提高,不过经过对比,我觉得 Trac 是一个不错的选择。

准备工作

  因为版本的更新,我列出的都是当前的下载链接,肯定将来会失效,那个时候就从官方网站进入找到相应的版本即可,同时注意版本要协调一致。

  从 SVN 网站:http://subversion.tigris.org/ 下载 SVN 相关程序:

  从 Python 网站:http://www.python.org/ 下载:

  从 Trac 网站:http://www.edgewall.org/ 下载:

安装

  • 解压缩 svn-win32 到目录 C:\SVN15。
  • 安装 Python:一路 next 即可,我是安装到了 C:\Python25。
  • 安装 svn-python,setuptools,Genshi,trac 这些都会自动识别 Python 目录。

  安装结束后,可以将 SVN 下的 bin 目录,以及 Python 下的 Scripts 目录加入到系统 PATH,方便后面的命令行输入。最好重启一下,有一些动态链接库可能需要重启后加载。

配置 Trac 环境

  因为我们要把 Trac 与 SVN 整合,因此首先需要有一个 SVN 的版本库,比如 D:\MySVN。假设我们希望在 D:\MyTrac 保存 Trac 的数据,输入:

D:\Python25\Scripts\trac-admin D:\MyTrac initenv

  这就开始了一个配置向导,其中红色部分是我的输入,[Enter]表示直接回车:

# 项目名称
Project Name [My Project]> [Enter]

# 数据库
Database connection string [sqlite:db/trac.db]> [Enter]

# 版本库类型
Repository type [svn]> [Enter]

# 版本库地址
Path to repository [/path/to/repos]> D:\MySVN

  这个时候,D:\MyTrac 就建立好了 Trac 的环境数据。如果这一步出现了错误,比如提示缺少 ssleay32.dll,重启一下再进行这步即可。

  启动 Trac 服务,输入:

D:\Python25\Scripts\tracd.exe --port 8000 D:\MyTrac

  在浏览器中输入:http://127.0.0.1:8000/MyTrac,就可以访问建立好的 Trac 页面了。

创建 Trac 密码文件

  在上述浏览页面,点击 Login 会提示 Authentication information not available. 因为我们没有使用 Apache,所以需要使用一个 Python 脚本来生成密码文件,这个脚本在 Trac 的官方 Wiki 上:Trac Standalone。这里原文复制,将下面的代码保存为genpsw.py:

from optparse import OptionParser
# The md5 module is deprecated in Python 2.5
try:
    from hashlib import md5
except ImportError:
    from md5 import md5

# build the options
usage = "usage: %prog [options]"
parser = OptionParser(usage=usage)
parser.add_option("-u", "--username",action="store", dest="username", type = "string",
                  help="the username for whom to generate a password")
parser.add_option("-p", "--password",action="store", dest="password", type = "string",
                  help="the password to use")
(options, args) = parser.parse_args()

# check options
if (options.username is None) or (options.password is None):
   parser.error("You must supply both the username and password")
   
# Generate the string to enter into the htdigest file
realm = 'trac'
kd = lambda x: md5(':'.join(x)).hexdigest()
print ':'.join((options.username, realm, kd([options.username, realm, options.password])))

  注意红色部分的 trac 这个要与下面命令行输入的红色 trac 保持一致。

# 生成密码
genpsw.py -u admin -p admin >> D:\MyTrac\password.txt

# 加入 admin 用户
trac-admin D:\MyTrac permission add admin TRAC_ADMIN

# 启动服务
tracd --port 8000 --auth *,D:\MyTrac\password.txt,trac D:\MyTrac

  这个时候,就可以用 admin : admin 登陆了。如果希望生成多个用户名和密码,则需要多次运行上述 Python 脚本,其中">>"的含义是追加到文件。这步本质上就是将密码的 md5 保存到本地,之后就用这个进行校验。而上面用到的 "TRAC_ADMIN" 是指管理员权限,这是 Trac 默认设置的一个权限,可以使用 trac-admin D:\MyTrac permission list 列出当前的用户和权限。在使用管理员账号登陆以后,可以方便的修改这些。

将 SVN 与 Trac 作为服务启动

  在 Windows 环境下,总是有一个命令行窗口是很碍事的事情,我们希望能把 SVN 与 Trac 作为系统的一个服务,开机就能自动启动。
  我们使用一个 Windows 自带的服务配置程序:sc,只要在命令行中输入:

sc create svnserve binPath= "\"C:\SVN15\bin\svnserve.exe\" --service --root D:\MySVN" displayname= "Subversion Repository" depend= Tcpip start= auto

sc create tracserve binPath= "\"C:\Python25\Scripts\tracd.exe\" --port 8000 --auth *,D:\MyTrac\password.txt,trac D:\MyTrac" displayname= "Trac" depend= Tcpip start= auto

  然后在服务中开启新加入的两项服务,重启就会发现它们都启动了。删除服务使用:

sc delete svnserve

  注:sc 的参数 binPath 要求用双引号括起来,如果路径还有空格,使用转义字符:\",sc 的详细使用可以看帮助。"--auth *" 表示所有项目用相同的账户登陆。"D:\MyTrac" 表示要启动的项目,如果有多个项目用逗号分开即可。

一些高级设置

  在 SVN 版本库 D:\MySVN\conf\svnserve.conf,可以设置代码的基本使用权限:

anon-access = read # 设置匿名只有读权限
auth-access = write # 设置登陆用户有写权限
authz-db = authz # 使用 authz 文件中的权限设置

  在 Trac 环境设置 D:\MyTrac\conf\trac.ini 中,可以把代码浏览的权限与 SVN 绑定:

authz_file = D:\MySVN\conf\authz

  注意到,这个权限绑定和 SVN 目录下面的 svnserve.conf 无关,也就是说,如果在 svnserve.conf 设置了匿名权限为 none,但是在 SVN 下的 authz 文件却没有体现这一点,则 Trac 中的代码浏览可能会允许匿名浏览。

  同样在 trac.ini 中,设置字符集可以解决中文显示问题(我设置成 UTF-8 就在浏览代码中的文本时时出现乱码):

default_charset = GBK

  如果发现有权限的用户登陆后浏览 SVN 库中的代码(即 Browse Source),会得到 "Insufficient permissions to access" 提示。这时,就要检查 trac.ini 文件里 "authz_file= " 如果设置了例如 D:\MySVN\FirstProj\conf\authz 这样的值,那么就要保证 authz_module_name 的值与 authz 这个文件里的值一致。比如在 authz 文件里作了这样的设置:[FirstProj:/],那么 authz_module_name 就应该等于 FirstProj。

附:参考

2
Posted on 下午4:44:00 by Fan Zhang and filed under

什么是 TortoiseSVN?

  SVN 全名是 Subversion,它是一个开源的版本控制软件,与它类似的软件有 CVS,VSS,ClearCase。只要接触过团队开发,对这类软件肯定不会陌生。而 SVN 作为一个跨平台的开源软件,具有很强的活力,目前也已经相当成熟,很多开源项目都用它来管理文档或是代码。

  更为重要的是,不仅仅是团队开发,作为个人独立开发的项目(或者个人想维护的文档)也可以用 SVN 进行管理,而不需要另外一台服务器。

  TortoiseSVN 是 SVN 的一个 Windows 外壳扩展应用,它可以帮助用户直观的进行 SVN 的各种操作,而不需要使用命令行。作为个人用户,只要安装 TortoiseSVN 即可,而不用再去安装配置 SVN。 

TortoiseSVN 快速入门

  下面我就来对 TortoiseSVN 从安装到第一个代码库的建立和使用做一个最简单的介绍。即使对 TortoiseSVN 一无所知,通过下面的操作,也可以初步领略 SVN 管理代码的乐趣。

  一,安装

  TortoiseSVN 的官方主页:http://tortoisesvn.net,首先下载当前版本的 TortoiseSVN,希望能有中文界面的还可以选择语言包下载。同时在语言包旁边,你还可以看到中文的使用手册。

  安装 TortoiseSVN 非常简单,在结束后会提示重启,这是因为 TortoiseSVN 与资源管理器整合,它的图标功能需要重启后才能使用,所以建议这里重启一下。

  这个时候,在任何一个文件夹点右键,就会出现如下的菜单:

TortoiseSVN_menu_settings.png

  如果是英文界面,那么在 TortoiseSVN --> Settings 中可以选择语言。TortoiseSVN 的所有操作都是通过右键菜单来完成的。

  二,创建版本库

  首先,我们要新建一个文件夹来保存 SVN 的数据,比如我们建立了一个空文件夹:"D:\MySVN"。在这个文件夹图标上点击右键,在菜单中选择:在此创建版本库,很快就会提示建立完成。

TortoiseSVN_menu_Repository.png

  这个时候,你会发现这个文件夹里面会增加好多文件,它将保存你的用户权限的设置以及所有的代码信息。现在不用管它,按照默认设置就可以很好工作。以后如果要在另外一台机器上修改代码,或者希望别人也能使用你的代码库,只要把这个文件夹复制过去就行。备份也是如此。

  注:从网上看早期的教程,那些文章在这一步会提到选择 Berkeley 数据库(BDB)或者本地文件系统(FSFS)。但是从 SVN 1.5 版本开始,已经取消了 BDB 的选择,直接默认的就是 FSFS。

  注:为了避免因为多字节字符造成的种种问题,建议把版本库的路径和名字不要含有中文或者空格。这个问题虽然可能随着软件的升级得到解决,不过目前看来,有时还会出问题。不过这个问题仅限于版本库,受管理的代码和目录可以任意取名。

  三,检出到工作目录

  完成上一步后,我们已经建立了一个代码仓库,下面就是要设置工作目录。工作目录一般来讲,就是存放了当前最新版本的代码,程序的编写和修改都在这个目录完成。比如我们在桌面选择一个文件夹,名叫 Project。在这个文件夹图标上,点击右键,选择:SVN 检出。

TortoiseSVN_menu_checkout.png

  然后在版本库 URL 中选择刚才创建的版本库:file:///D:/MySVN,点击确定,就开始从版本库中获取代码了。

TortoiseSVN_checkout.png

  自然,因为我们版本库是空的,所有什么代码也没有。如果你打开隐藏文件显示,会发现多了一个 .svn 的文件夹,它存放的是本地文件版本控制的信息,不要删除或者修改它,以后工作目录的每层路径都会有 .svn 文件夹。为了防止误删这个文件夹,我们不显示隐藏文件。

  刷新一下桌面,会发现我们的 Project 文件的图标左下角会多出一个绿色的对号,这表明它已经纳入了版本控制。

  注:你可以在任何地方多次检出。

  四,提交入库

  第一次向版本库中加入代码可以使用导入的功能,不过我还是喜欢直接添加文件。比如我向 Project 中复制了几个目录和文件。因为这些文件是新增的,所以自动会用问号来标记。

TortoiseSVN_addfile.png

  然后我希望把这些文件存放到代码仓库中,这个时候,在 Project 文件夹内点击右键,选择:SVN 提交,然后勾选"全选",把新增的所有文件都纳入版本控制,点击确定。

TortoiseSVN_commit.png

  五,版本管理

   我们开始工作,比如新增文件、修改文件、删除文件,你会发现所有修改过的文件都会有一个红色叹号来标记。当觉得工作进行到一定阶段,有必要保存一下的时候,我们可以再次进行提交。因为现在讲解的是一个人使用,所以很少会再次检出或者进行更新,但这在团队开发中很常用。

  如果你发现你这次的修改有问题,想恢复版本库中最新的版本,只要把这个文件删除,并选择更新即可。

  在某种情况下,要恢复一个很久之前的版本,这个时候只要点击右键,选择:显示日志,在想复原的版本上点右键,选择:复原到此版本。

TortoiseSVN_revert.png

  通过上面简单的介绍,希望能带大家入门。更多的操作可以参考官方的文档,非常详细。

20
Posted on 上午12:07:00 by Fan Zhang and filed under ,

  Blogger 虽然解封可以访问,但是它与发布有关的 API 却被封了多时。因此这一段时间我都只能使用 Blogger 的后台发表文章,Windows Live Writer 和 Zoundey Raven 都不能用了。

  我曾经尝试过使用代理,不过始终不太稳定,虽然成功过,但却多数情况下仍然会出错。我的想法就是使用 Blogger 的 SSL 链接再加上 HTTP 代理(比如使用 Tor)来访问,但之前的文章也提到,当时的 Raven 还有些问题。

  今天我不死心,继续去官方论坛看,发现 0.9.363 版本发布了,它解决了通过普通的 HTTP 代理访问 Blogger 的 HTTPS API 的问题。

  于是,我使用 Tor + Privoxy 设置代理如下:

  • 在 Zoundry Raven 的工具-->偏好设置-->常规-->代理中设置:127.0.0.1:8118,这个是使用 Privoxy 的默认端口。如果使用别的代理,理论上可行,不过我没有多试验。
  • 在 Blog 的设置-->API 信息中,将原本的 http://www.blogger.com/feeds/default/blogs 中的 http 改为 https。

  这样就可以使用了。

0
Posted on 上午1:10:00 by Fan Zhang and filed under

今天终于有闲暇时间坐下来看 Code Geass,当看到连鲁路修都当 CEO 的时候,突然觉得有点想喝饮料...于是就去了自动售货机。

虽说这台破机器经常要么不认硬币,要么不认纸币,但在我两手准备下,依然吃进了我 3.5 元钱。我决定喝一瓶果粒橙,因为它的标签上写着:Cold, 夏天喝冷饮看动画多么享受啊。

结果这家伙竟然给我吐出一瓶热的!更神奇的是,它根本没有制热的功能,纯粹是机器内部的热量就达到如此神奇的功效,冬天怎么就没发现呢?

还是原来楼里的自动售货机好,虽然东西经常挂在上面掉不下来,但多买几个总会下来的。至少那台不会骗我,饮料是凉的。

哦,突然还想起,这台光吃饭不制冷的自动售货机还干过一件缺德事。那次我先扔进一元硬币,想了想还是不喝饮料了,于是就按了退币,结果竟然掉下一个一角的!难道它的机制不是我扔进什么还退出什么吗?而且,里面怎么会有一角的硬币呢?

4
Posted on 上午1:39:00 by Fan Zhang and filed under

原谅我恶俗的名字,其实就是介绍两个扩展。

我喜欢将一些常用的网站,脚本(如 iMacros ), Bookmarklet(一些 javascript)放在书签工具栏中,使用起来比较方便。因为它们很常用,所以不用显示文字,只是一个图标(Favicon)就行。另外,有些网站没有图标(自己写的脚本也没有),或者图标很难看,就需要手动修改。在 Firefox 2 的时候,书签就是一个 html 文件,修改起来比较方便。但在 Firefox 3 中,书签系统变得很智能,保存是用 SQLite 数据库文件,不太容易修改(一个笨的方法就是"导出HTML"->修改->"导入HTML")。而且,有一个致命的问题是,Firefox 会自动用网站本身的图标替换我修改后的图标,可能有设置能改,但是我不知道。

下面就来介绍两个扩展实现我的目的,非常好用。

  • Smart Bookmarks Bar:实现在工具栏中只显示图标。
  • Favicon Picker:可以自定义任何书签的图标,并且不会被网站默认的图标自动取代。

0
Posted on 上午12:27:00 by Fan Zhang and filed under

使用高版本的 Visual Studio 打开低版本创建的项目(工程、解决方案)文件时,会自动转化到高版本。但这个过程是不可逆的,即高版本创建的项目(解决方案)文件不能在低版本中打开。

因为新的版本会加入很多新的特性,所以项目文件不能向下兼容。如果不得不在低版本中打开高版本创建的项目文件时,可以尝试采用手动修改解决方案文件和项目文件。

对于不同版本的 Visual Studio 生成的项目(解决方案)文件所标记的版本号是不同的,如果强制修改,则可以跳过 Visual Studio 的检查,一般就可以打开了。只是如果使用了新版本的某些特性,则可能出现一些问题。用文本编辑器打开项目(解决方案)文件,你会发现含有如下的版本标记。

Product Name Product Version File Format
Visual Studio .Net
v7.0
7
Visual Studio .Net 2003
v7.1
8
Visual Studio 2005
v8.0
9
Visual Studio 2008
v9.0
10

下面示例中标记出来的部分就是需要修改的地方。

解决方案文件(.sln)


Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ProjectConverter", 
 "ProjectConverter.vbproj", "{B637ACFD-0AFC-4FBB-A8C0-602B5ABA62F0}"
EndProject
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Setup", "Setup\Setup.vdproj", 
 "{09667F41-0E35-4D40-A0A9-E71BA6740D93}"
EndProject
Global

 ....

EndGlobal

项目文件(.vbproj, .csproj, .vcproj)


<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

    <ProductVersion>9.0.21022</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{B637ACFD-0AFC-4FBB-A8C0-602B5ABA62F0}</ProjectGuid>
    <OutputType>WinExe</OutputType>

    <StartupObject>ProjectConverter.My.MyApplication</StartupObject>
    <RootNamespace>ProjectConverter</RootNamespace>
    <AssemblyName>ProjectConverter</AssemblyName>
    <FileAlignment>512</FileAlignment>

    <MyType>WindowsForms</MyType>
    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
    <OptionExplicit>On</OptionExplicit>
    <OptionCompare>Binary</OptionCompare>

    ...

</Project>

一般来说,将这些版本号修改了就可以打开了。准备写本文的时候,搜索到一篇:Visual Studio 2005/2008 Interoperability,还提到了更多可以修改的地方,本文的示例就是我偷懒复制来的,而且还给出了一个小工具,有需要的可以下载试试。