乐者为王

Do one thing, and do it well.

Git笔记之项目创建

Git的官网地址:https://git-scm.com/

学习路线推介:新手请浏览gittutorial(7),然后是Everyday Git,接着是“git help command”,需要更全面的了解Git请看Git User's Manual

1、初始化仓库

1
2
3
mkdir gittest
cd gittest
git init  # 创建.git隐藏目录,即所谓的Git仓库,用来存储项目的所有历史和元信息

2、告诉项目你的信息

1
2
git config --global user.name "yourname"
git config --global user.email yourname@example.com

3、跟踪新文件

1
2
echo 'Hello Git!' > greeting
git add greeting

这里Git给greeting这个文件的内容生成快照,并把快照存储在Git称之为索引的暂存区。你也可以使用git add .来将当前目录下所有的文件内容加入到暂存区。

4、查看项目当前状态

1
git status

5、提交内容到仓库

1
git commit  # 将暂存区的内容写入仓库

在输入git commit后按回车会跳出一个文本编辑器窗口,要求开发者输入这次提交的开发信息。

git commit的选项:

  • -s 在提交日志信息末尾添加提交者的Signed-off-by行。
  • -m 使用给定的信息作为提交信息。没有该选项会自动打开一个编辑器以填写提交信息。
  • -a 自动将修改过的文件添到暂存区中(新建但没有git add的文件不会受到影响)。

6、查看项目历史

1
git log

如果你想看下每次提交的大致变动情况,可使用以下命令:

1
git log --stat --summary

使用WinDbg检测内存泄漏

英文原文:https://www.codeproject.com/Articles/31382/Memory-Leak-Detection-Using-WinDbg

简介

内存泄漏是一种费时的bug,通常由C++开发者制造。内存泄漏的检测经常是令人厌烦的。如果代码不是你写的,或者代码库相当巨大,事情就会变得很糟糕。

尽管市场上有可用的工具帮助你检测内存泄露,但这些工具大多数不是免费的。我发现WinDbg作为一个免费的强大的工具可以用来解决内存泄漏bug。至少,我们可以知道可能涉嫌引起内存泄漏的代码位置。COM接口泄漏不在这篇文章范围内。

WinDbg是来自Microsoft的一个强大的用户/内核空间调试器,它可以从这里下载和安装。

使用WinDbg

开始使用WinDbg:

  1. 配置符号文件路径指向Microsoft符号服务器SRV*d:\symbols*http://msdl.microsoft.com/download/symbols
  2. 将你的程序EXE/DLL的PDB(程序数据库)路径添加到符号文件路径中;
  3. 你还需要配置操作系统的标记去启用有内存泄漏的进程上的用户栈跟踪。这很简单,可以用gflags.exe做到。gflags.exe在WinDbg安装期间被安装。或者也可以通过命令行来完成,使用命令gflags.exe /i MemoryLeak.exe +ust即可。我的程序名是Test2.exe。因此,为了演示,需要用Test2.exe替换掉MemoryLeak.exe。下面的快照显示了应用Test2.exe的OS标记的设置。

一旦我们配置好WinDbg的符号文件路径,开启泄漏内存的进程,就可以把WinDbg挂载上去。挂载选项可以在WinDbg的File菜单下找到,或者可以使用F6快捷键启动。下面的快照显示了挂载界面:

WinDbg的!heap命令用来显示堆。在WinDbg帮助文件里有!heap的详尽文档。

我已经开发了一个泄漏内存的小程序,在后面也将使用这个程序来做演示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int _tmain(int argc, _TCHAR* argv[])
{
    while(1)
    {
        AllocateMemory();
    }
    return 0;
}
void AllocateMemory()
{
    int* a = new int[2000];
    ZeroMemory(a, 8000);
    Sleep(1);
}

上面的程序泄漏一个大小为2000*4字节的整型数组。

把WinDbg挂载到进程上后,执行命令!heap -s。-s代表概要。下面是泄漏进程上!heap -s的输出:

1
2
3
4
5
6
7
8
9
10
11
12
0:001> !heap -s
NtGlobalFlag enables following debugging aids for new heaps:
    validate parameters
    stack back traces
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast
                    (k)     (k)    (k)     (k) length      blocks cont. heap
-----------------------------------------------------------------------------
   00150000 58000062    1024     12     12      1     1     1    0      0   L
   00250000 58001062      64     24     24     15     1     1    0      0   L
   00260000 58008060      64     12     12     10     1     1    0      0
   00330000 58001062   64576  47404  47404     13     4     1    0      0
-----------------------------------------------------------------------------

让进程执行一段时间,然后重新进入进程,再次执行!heap -s。下面显示的是该命令的输出:

1
2
3
4
5
6
7
8
9
10
11
12
0:001> !heap -s
NtGlobalFlag enables following debugging aids for new heaps:
   validate parameters
   stack back traces
   Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast
                     (k)     (k)    (k)     (k) length      blocks cont. heap
   -----------------------------------------------------------------------------
    00150000 58000062    1024     12     12      1     1     1    0      0   L
    00250000 58001062      64     24     24     15     1     1    0      0   L
    00260000 58008060      64     12     12     10     1     1    0      0
    00330000 58001062  261184 239484 239484     14     4     1    0      0
   -----------------------------------------------------------------------------

第11行显示了增长堆。上面的快照显示一个句柄为00330000的堆在增长。

执行!heap -stat -h 00330000。这个命令用来显示增长堆的堆统计。下面显示的是该命令的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
0:001> !heap -stat -h 00330000
heap @ 00330000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    1f64 76c6 - e905f58  (99.99)
    1800 1 - 1800  (0.00)
    824 2 - 1048  (0.00)
    238 2 - 470  (0.00)
    244 1 - 244  (0.00)
    4c 5 - 17c  (0.00)
    b0 2 - 160  (0.00)
    86 2 - 10c  (0.00)
    50 3 - f0  (0.00)
    74 2 - e8  (0.00)
    38 4 - e0  (0.00)
    48 3 - d8  (0.00)
    c4 1 - c4  (0.00)
    62 2 - c4  (0.00)
    be 1 - be  (0.00)
    b8 1 - b8  (0.00)
    ae 1 - ae  (0.00)
    ac 1 - ac  (0.00)
    55 2 - aa  (0.00)
    a4 1 - a4  (0.00)

上面的快照显示大小为1f64的76c6个块被分配(第5行)。如此巨大的相同大小的块的数量让我们怀疑这些可能是泄漏块。其余的块分配没有在增长的块数字。

下一步是去获得这些块的地址。使用命令!heap -flt s 1f64。这个命令过滤出堆的所有其它块,并且显示大小为1f64的块的详细信息。

下面显示的是该命令的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
0:001> !heap -flt s 1f64
    _HEAP @ 150000
    _HEAP @ 250000
    _HEAP @ 260000
    _HEAP @ 330000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        003360e0 03f0 0000  [07]   003360e8    01f64 - (busy)
        00338060 03f0 03f0  [07]   00338068    01f64 - (busy)
        00339fe0 03f0 03f0  [07]   00339fe8    01f64 - (busy)
        0033bf60 03f0 03f0  [07]   0033bf68    01f64 - (busy)
        0033dee0 03f0 03f0  [07]   0033dee8    01f64 - (busy)
        01420040 03f0 03f0  [07]   01420048    01f64 - (busy)
        01421fc0 03f0 03f0  [07]   01421fc8    01f64 - (busy)
        01423f40 03f0 03f0  [07]   01423f48    01f64 - (busy)
        01425ec0 03f0 03f0  [07]   01425ec8    01f64 - (busy)
        01427e40 03f0 03f0  [07]   01427e48    01f64 - (busy)
        01429dc0 03f0 03f0  [07]   01429dc8    01f64 - (busy)
        0142bd40 03f0 03f0  [07]   0142bd48    01f64 - (busy)
        0142dcc0 03f0 03f0  [07]   0142dcc8    01f64 - (busy)
        0142fc40 03f0 03f0  [07]   0142fc48    01f64 - (busy)
        01431bc0 03f0 03f0  [07]   01431bc8    01f64 - (busy)
        01433b40 03f0 03f0  [07]   01433b48    01f64 - (busy)
        01435ac0 03f0 03f0  [07]   01435ac8    01f64 - (busy)
        01437a40 03f0 03f0  [07]   01437a48    01f64 - (busy)
        014399c0 03f0 03f0  [07]   014399c8    01f64 - (busy)
        0143b940 03f0 03f0  [07]   0143b948    01f64 - (busy)
        0143d8c0 03f0 03f0  [07]   0143d8c8    01f64 - (busy)
        0143f840 03f0 03f0  [07]   0143f848    01f64 - (busy)
        014417c0 03f0 03f0  [07]   014417c8    01f64 - (busy)
        01443740 03f0 03f0  [07]   01443748    01f64 - (busy)
        014456c0 03f0 03f0  [07]   014456c8    01f64 - (busy)
        01447640 03f0 03f0  [07]   01447648    01f64 - (busy)
        014495c0 03f0 03f0  [07]   014495c8    01f64 - (busy)
        0144b540 03f0 03f0  [07]   0144b548    01f64 - (busy)
        0144d4c0 03f0 03f0  [07]   0144d4c8    01f64 - (busy)
        0144f440 03f0 03f0  [07]   0144f448    01f64 - (busy)
        014513c0 03f0 03f0  [07]   014513c8    01f64 - (busy)
        01453340 03f0 03f0  [07]   01453348    01f64 - (busy)
        014552c0 03f0 03f0  [07]   014552c8    01f64 - (busy)
        01457240 03f0 03f0  [07]   01457248    01f64 - (busy)
        014591c0 03f0 03f0  [07]   014591c8    01f64 - (busy)
        0145b140 03f0 03f0  [07]   0145b148    01f64 - (busy)
        0145d0c0 03f0 03f0  [07]   0145d0c8    01f64 - (busy)
        0145f040 03f0 03f0  [07]   0145f048    01f64 - (busy)
        01460fc0 03f0 03f0  [07]   01460fc8    01f64 - (busy)
        01462f40 03f0 03f0  [07]   01462f48    01f64 - (busy)
        01464ec0 03f0 03f0  [07]   01464ec8    01f64 - (busy)
        01466e40 03f0 03f0  [07]   01466e48    01f64 - (busy)
        01468dc0 03f0 03f0  [07]   01468dc8    01f64 - (busy)

使用任何来自上面输出中的UsrPtr列值,然后使用命令!heap -p -a UsrPtr去显示UsrPtr的调用栈。我选择了第27行的0143d8c8。

执行!heap -p -a 0143d8c8,我们得到下面显示的调用栈:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0:001> !heap -p -a 0143d8c8
    address 0143d8c8 found in
    _HEAP @ 330000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0143d8c0 03f0 0000  [07]   0143d8c8    01f64 - (busy)
        Trace: 0025
        7c96d6dc ntdll!RtlDebugAllocateHeap+0x000000e1
        7c949d18 ntdll!RtlAllocateHeapSlowly+0x00000044
        7c91b298 ntdll!RtlAllocateHeap+0x00000e64
        102c103e MSVCR90D!_heap_alloc_base+0x0000005e
        102cfd76 MSVCR90D!_heap_alloc_dbg_impl+0x000001f6
        102cfb2f MSVCR90D!_nh_malloc_dbg_impl+0x0000001f
        102cfadc MSVCR90D!_nh_malloc_dbg+0x0000002c
        102db25b MSVCR90D!malloc+0x0000001b
        102bd691 MSVCR90D!operator new+0x00000011
        102bd71f MSVCR90D!operator new[]+0x0000000f
        4113d8 Test2!AllocateMemory+0x00000028
        41145c Test2!wmain+0x0000002c
        411a08 Test2!__tmainCRTStartup+0x000001a8
        41184f Test2!wmainCRTStartup+0x0000000f
        7c816fd7 kernel32!BaseProcessStart+0x00000023

第16-19行显示了来自我们代码的函数。

注意:有时候,可能发生!heap -s命令不显示增长堆的情况。如果那样的话,使用!heap -stat -h命令列出带有堆的大小和块的数量的所有堆。识别在增长的块的数量,然后使用!heap -flt s SIZE(SIZE = 涉嫌块的大小)命令。

VirtualBox虚拟Ubuntu 8.10时共享文件夹的使用

我的环境:主机操作系统是Windows Server 2008,虚拟机操作系统是Ubuntu 8.10,虚拟机是VirtualBox 2.0.4。

安装增强功能包(Guest Additions)

安装好Ubuntu 8.10后,运行Ubuntu并登录。然后在VirtualBox的菜单里选择“Devices” -> “Install Guest Additions”。如图所示:

你会发现在Ubuntu桌面上多出一个光盘图标,这张光盘默认被自动加载到了文件夹/media/cdrom0。在命令行下输入:

1
2
cd /media/cdrom0
sudo ./VboxLinuxAdditions.run

开始安装工具包。安装完毕后会提示要重启Ubuntu。

设置共享文件夹

重启完成后点击“Devices” -> “Shared Folders”菜单,添加一个共享文件夹,选项“Make Permanent”是指该文件夹是否是持久的。共享名可以任取一个自己喜欢的,比如“flamingo”,尽量使用英文名称。

挂载共享文件夹

重新进入虚拟Ubuntu,打开命令行窗口输入:

1
2
sudo mkdir /mnt/shared
sudo mount -t vboxsf flamingo /mnt/shared

其中“flamingo”是之前创建的共享文件夹的名字。现在Ubuntu和主机可以分享文件了。

假如你不想每一次都手动挂载,可以在/etc/fstab中添加一项:

1
flamingo /mnt/shared vboxsf defaults 0 0

这样每次系统启动时就能够自动挂载了。

需要注意的是,共享文件夹的名称千万不要和挂载点的名称相同。比如,上面的挂载点是/mnt/shared,如果共享文件夹的名字也是shared的话,在挂载的时候就会出现如下的错误信息(看 http://www.virtualbox.org/ticket/2265 ):

1
/sbin/mount.vboxsf: mounting failed with the error: Protocol error

原因分析可以看Tips on running Sun Virtualbox的Shared Folder on a Linux Guest节。

卸载的话使用下面的命令:

1
sudo umount -f /mnt/shared

2017/7/11更新

在设置共享文件夹时,如果勾选了“Auto-mount”,那么Ubuntu会自动在/media里建立以“sf_”为前缀并加上共享名的挂载点。不过因为这个挂载点默认的权限是给vbox创建的用户组“vboxsf”的,所以你会无法查看,可以修改/etc/group,把自己的用户名加到“vboxsf”组解决。并且,在这种情况下你通过手动修改/etc/fstab以实现自动挂载会失败。所以,若想通过修改/etc/fstab实现自动挂载,在设置共享文件夹时就不能勾选“Auto-mount”。

关于input[text]里的光标定位

当使用Tab键切换时,想把光标定位在input[text]的首部。在网上找了一些光标定位的资料发现大多数都是用createTextRange来实现的,而且都出自一个实例。可惜的是在Firefox下createTextRange无效。

后来在Firefox的开发者站点上发现有个setSelectionRange方法可以实现这样的功能。使用格式:

1
2
3
4
5
o.setSelectionRange(start, end);

o:为文本输入框对象
start:为字符串的起始位置
end:为字符串的末位置

尝试后发现并不能定位到文本首位,总是全选所有的文本内容,在后面加上获的焦点的命令也不管用。最后还是在国外的一个站点上找到了解决的办法。

下面的代码在Firefox下不能定位到首位,只能选中全部:

1
2
3
4
5
6
7
8
9
10
11
12
function setCaretPosition(aCtrl, aPos) {
    if (aCtrl.setSelectionRange) {
        aCtrl.setSelectionRange(aPos, aPos);
        aCtrl.focus();
    } else if (aCtrl.createTextRange) {
        var rng = aCtrl.createTextRange();
        rng.collapse(true);
        rng.moveStart('character', aPos);
        rng.moveEnd('character', aPos);
        rng.select();
    }
}

经过修改后的代码就可以适用于Firefox,IE,Opera的光标定位了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function setCaretPosition(aCtrl, aPos) {
    if (aCtrl.setSelectionRange) {
        setTimeout(function() {
            aCtrl.setSelectionRange(aPos, aPos);
            aCtrl.focus();
        }, 0);
    } else if (aCtrl.createTextRange) {
        var rng = aCtrl.createTextRange();
        rng.collapse(true);
        rng.moveStart('character', aPos);
        rng.moveEnd('character', aPos);
        rng.select();
    }
}

Ubuntu 8.10英文Locale下安装Fcitx中文输入法

系统装好后首先要做的就是安装中文输入法。在网上找了一些中文输入法的资料,最常用的是Fcitx和SCIM输入法。不过好像SCIM的问题比较多,而且据说Fcitx的功能上也要比SCIM强得多,所以决定采用Fcitx输入法。

卸载SCIM

为了避免安装中出现一些问题,在这之前先要卸载掉系统自带的SCIM输入法:

1
2
3
sudo apt-get remove --purge scim*  # 删除SCIM及其配置文件
sudo apt-get autoremove  # 删除被SCIM依赖的,不再使用的package
sudo apt-get install -f  # 尝试修正安装过程中出现的依赖性关系

注:也可以通过“新立得软件包管理器(Synaptic Package Manager)”来卸载SCIM。

安装Fcitx

下载最新的稳定的预编译包 http://www.fcitx.org/download/fcitx-3.4.2-bin.tar.bz2 ,解压到任意目录。启动命令行,进行该目录执行sudo ./fcitx.install进行安装(只是复制了几个文件到目标目录)。反安装也是在该目录下面执行sudo ./fcitx.uninstall(如果知道安装到哪了直接删除也行)。

因为要在英文Locale下启动Fcitx输入法,所以在/etc/X11/xinit/xinput.d/下新建一个文件en_US,文件内容如下:

1
2
3
4
5
6
7
XMODIFIERS="@im=fcitx"
XIM=fcitx
XIM_PROGRAM=/usr/bin/fcitx
XIM_ARGS=""
GTK_IM_MODULE=XIM
QT_IM_MODULE=XIM
DEPENDS="fcitx"

执行ls -l /etc/X11/xinit/xinput.d命令,输出以下内容:

1
2
3
4
5
6
7
8
9
10
11
total 24
drwxr-xr-x 2 root root 4096 2008-10-30 07:10 .
drwxr-xr-x 3 root root 4096 2008-10-30 07:03 ..
lrwxrwxrwx 1 root root   32 2008-11-05 00:31 all_ALL -> /etc/alternatives/xinput-all_ALL
-rw-r--r-- 1 root root 1152 2008-01-08 18:41 default
-rw-r--r-- 1 root root  601 2008-01-08 18:41 default-xim
-rw-r--r-- 1 root root  601 2008-01-08 18:41 en_US
-rw-r--r-- 1 root root  474 2008-01-08 18:41 none
-rw-r--r-- 1 root root  451 2008-10-27 05:54 scim-bridge
lrwxrwxrwx 1 root root   30 2008-11-05 00:31 th_TH -> /etc/alternatives/xinput-th_TH
-rw-r--r-- 1 root root  610 2008-01-08 18:41 th-xim

重启X Window后Fcitx正常启动,输入条位于屏幕顶端,但是按Ctrl+Space无法调出中文输入,用鼠标点小企鹅也不行。这时需要编辑/usr/lib/gtk-2.0/2.10.0/immodule-files.d/libgtk2.0-0.immodules文件,找到:

1
"xim" "X Input Method" "gtk20" "/usr/share/locale" "ko:ja:th:zh"

将之改成

1
"xim" "X Input Method" "gtk20" "/usr/share/locale" "en:ko:ja:th:zh"

使Xim在英文环境下也能启动。保存退出,重启X后中文输入就可以被正常调出了。

安装中文所需的Locale包

现在还有个问题就是输入法尾部出现乱码,输入条下的待选字也是乱码,即只显示一些小方框,如下图:

这是因为缺少中文Locale文件导致,需要安装两个中文Locale包。

1
2
sudo apt-get install language-pack-zh
sudo apt-get install language-pack-gnome-zh

或者,也可以将~/.fcitx/config中的:

1
显示字体(中)=*

改成

1
显示字体(中)=AR PL UMing CN  # 填你喜欢的中文字体

重新启动后就没有乱码了。

修改Ubuntu 8.10的sources.list

系统自带的软件源速度太慢,更新一次安装包竟然要4个多小时,决定换个快点的软件源。这里 http://wiki.ubuntu.org.cn/Template:8.10source 列出了选多的选择,我选择了最下面的台湾官方源。

1
2
3
4
5
6
7
8
9
10
deb http://tw.archive.ubuntu.com/ubuntu intrepid main restricted universe multiverse
deb http://tw.archive.ubuntu.com/ubuntu intrepid-security main restricted universe multiverse
deb http://tw.archive.ubuntu.com/ubuntu intrepid-updates main restricted universe multiverse
deb http://tw.archive.ubuntu.com/ubuntu intrepid-backports main restricted universe multiverse
deb http://tw.archive.ubuntu.com/ubuntu intrepid-proposed main restricted universe multiverse
deb-src http://tw.archive.ubuntu.com/ubuntu intrepid main restricted universe multiverse
deb-src http://tw.archive.ubuntu.com/ubuntu intrepid-security main restricted universe multiverse
deb-src http://tw.archive.ubuntu.com/ubuntu intrepid-updates main restricted universe multiverse
deb-src http://tw.archive.ubuntu.com/ubuntu intrepid-backports main restricted universe multiverse
deb-src http://tw.archive.ubuntu.com/ubuntu intrepid-proposed main restricted universe multiverse

首先备份sources.list

1
sudo cp /etc/apt/sources.list /etc/apt/sources.list.original

然后用vi打开sources.list,把上面列出的源添加进去:

1
sudo vi /etc/apt/sources.list

接着就是更新源:

1
sudo apt-get update

现在我们就可以更新已安装的软件包了:

1
apt-get upgrade

升级已安装的包为最新版本,不会安装新的或移除老的安装包。如果一个包因为改变了倚赖关系而需要安装一个新的包,那么它将不会被升级,会被标志为hold。建议使用“-u”选项,这样你就能看到哪些安装包将会被升级。

如何设置数据窗口中某行某列的背景颜色

假设数据窗口有多行数据,在修改某个Cell的数据后希望能将该Cell的背景色变成红色,代码该如何写呢?

要对某行某列的属性进行更改,可以使用modify函数。在对某行某列的属性进行改变时,你需要先判断当前行是否是被修改数据的那行,如果知道行号的话(例如在itemchanged事件中),你可以使用下面的代码:

1
dw_main.modify(ls_colname + "background.color = '0~tIf(getrow() = " + string(row) + ", 255, 16777215)'")

当然,你也可以这么写:

1
dw_main.modify(ls_colname + "background.color = '0~tIf(getrow() = currentrow(), 255, 16777215)'")

修复wxWidgets Wizard for Visual Studio 2005/2008中的一个bug

前面发布的wxWidgets Wizard for Visual Studio 2005/2008存在一个bug,安装在VS2008中后不能创建新的wxWidgets项目。原因是没有将wxAppWiz.vsz文件中VsWizardEngine的版本号改为9.0。现在做了一些修改,修改后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
procedure CurStepChanged(CurStep: TSetupStep);
var
    i: Integer;
    Signature: String;
    ConfigLine: String;
    ConfigFile: String;
    ConfigFileLines: TArrayOfString;
begin
    if CurStep = ssPostInstall then begin
        if (Pos('Visual Studio 9.0', ExpandConstant('{app}')) > 0) then begin
            Signature := 'Wizard=VsWizard.VsWizardEngine';
            ConfigFile := ExpandConstant('{app}\VCProjects\wxAppWiz.vsz');
            LoadStringsFromFile(ConfigFile, ConfigFileLines);
            for i := 0 to GetArrayLength(ConfigFileLines) - 1 do begin
                if (Pos(Signature, ConfigFileLines[i]) > 0) then begin
                    ConfigFileLines[i] := 'Wizard=VsWizard.VsWizardEngine.9.0'
                    SaveStringsToFile(ConfigFile, ConfigFileLines, False);
                    break;
                end;
            end;
        end;

        Signature := 'wxWidgets';
        ConfigLine := 'wxWidgets|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1043|70' + #13#10;
        ConfigFile := ExpandConstant('{app}\VCProjects\vc.vsdir');
        LoadStringsFromFile(ConfigFile, ConfigFileLines);
        for i := 0 to GetArrayLength(ConfigFileLines) - 1 do begin
            if (Pos(Signature, ConfigFileLines[i]) > 0) then abort;
        end;
        SaveStringToFile(ConfigFile, ConfigLine, True);
    end;
end;

代码下载:https://github.com/dohkoos/wxwizard

com.sybase.jdbc2.jdbc.SybSQLException: SQL Anywhere Error -143: Column '@p3' not found

数据库:Sybase ASA 10

在移植PB程序到Java程序时,碰到了如下的嵌入式SQL语句:

1
2
3
4
5
6
7
8
9
10
SELECT DISTINCT
    bhr_emp_job.emp_nbr,
    bhr_emp_job.cyr_nyr_flg,
    bhr_emp_job.pay_freq,
    bhr_emp_job.job_cd,
    bhr_emp_job.contr_non_std_flg,
    bhr_emp_job.pay_type
FROM bhr_emp_job
WHEN :as_cal_code <> ''
AND :as_cal_code = bhr_emp_job.cal_cd

转换后的SQL代码如下:

1
2
3
4
5
6
7
8
9
10
SELECT DISTINCT
    bhr_emp_job.emp_nbr,
    bhr_emp_job.cyr_nyr_flg,
    bhr_emp_job.pay_freq,
    bhr_emp_job.job_cd,
    bhr_emp_job.contr_non_std_flg,
    bhr_emp_job.pay_type
FROM bhr_emp_job
WHEN ? <> ''
AND ? = bhr_emp_job.cal_cd

结果在执行的时候出现了下面的异常:

1
2
3
4
5
6
7
8
9
10
11
<ERROR>openQuery in org.rsccc.dao.hrs4300.DHrs4300JobcopyDao when executing SELECT DISTINCT
    bhr_emp_job.emp_nbr,
    bhr_emp_job.cyr_nyr_flg,
    bhr_emp_job.pay_freq,
    bhr_emp_job.job_cd,
    bhr_emp_job.contr_non_std_flg,
    bhr_emp_job.pay_type
FROM bhr_emp_job
WHEN ? <> ''
AND ? = bhr_emp_job.cal_cd
com.sybase.jdbc2.jdbc.SybSQLException: SQL Anywhere Error -143: Column '@p3' not found

在Sybase站点上找到的相关资料是Column '%1' not found

Probable cause: You misspelled the name of a column, or the column you are looking for is in a different table.

想到在PB中是在填充变量值后再将SQL语句扔到数据库中执行,而移植后的Java程序中采用的是PreparedStatement来执行SQL语句,所以会出现Column not found的错误。解决方法是将?移到赋值符号的右边:

1
2
3
4
5
6
7
8
9
10
SELECT DISTINCT
    bhr_emp_job.emp_nbr,
    bhr_emp_job.cyr_nyr_flg,
    bhr_emp_job.pay_freq,
    bhr_emp_job.job_cd,
    bhr_emp_job.contr_non_std_flg,
    bhr_emp_job.pay_type
FROM bhr_emp_job
WHEN '' <> ?
AND bhr_emp_job.cal_cd = ?

在EGit-0.3.1中使用Compare With Git Revision

EGit是一个Eclipse环境下的Git客户端插件,EGit的0.3.1版本已经提供了Compare With Revision功能,只是还没有注册到plugin.xml中。所以要使用该功能的话,必须自己动手在ui包中的plugin.xml中添加一些代码,即下面的action部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<objectContribution
        adaptable="true"
        id="org.spearce.egit.ui.fileFolderContributions"
        objectClass="org.eclipse.core.resources.IResource">
    <filter name="projectPersistentProperty"
        value="org.eclipse.team.core.repository=org.spearce.egit.core.GitProvider">
    </filter>
    <action
        class="org.spearce.egit.ui.internal.actions.CompareWithRevisionAction"
        id="org.spearce.egit.ui.internal.actions.CompareWithRevisionAction"
        label="%CompareWithRevisionAction_label"
        menubarPath="compareWithMenu/compareWithGroup"
        overrideActionId="org.eclipse.team.ui.compareLocalHistory"
        tooltip="%CompareWithRevisionAction_tooltip" />
</objectContribution>

另外,还要将CompareWithRevisionAction.java中run方法里的super.action(action)注释掉,否则会报StackOverflowException。

1
2
public void run(IAction action) {
    // super.action(action);