一点看法,也不知道对不对!来讨论一下,无论对错都给分!
PChar的修改问题:
在使用StrMove和Move等过程中经常会产生问题。例如以下代码
var
Ps1,Ps2:PChar;
begin
Ps1 := 'ABCDEF';
Ps2 := 'GHIJKL';
Move(Ps1[0], Ps2[0], 3); //Error
//Ps1[0] := 'Z'
end;
以上代码初看没有什么问题,然而实际运行发现在Move句出错了!而且对于//Ps1[0] := 'Z' 这句也会出错。
考察String的使用
var
Ps1,Ps2:String;
begin
Ps1 := 'ABCDEF';
Ps2 := 'GHIJKL';
Move(Ps1[1], Ps2[1], 3);
//Ps1[1] := 'Z'
end;
这里却表现十分正常。
那么原因在哪里呢?
分析: 在第一段代码中,Ps1 := 'ABCDEF'此句的赋植操作是个单纯的指针操作。即将存放'ABCDEF'的地址赋值给Ps1,但是'ABCDEF'的地址空间是在进程的地址空间,通俗的说就是和执行代码在同一空间。而不是在进程分配的堆的地址空间。由于进程的地址空间是受系统保护的,可读不可写。因此,对这个地址进行写就会出错。因此,考虑改成以下代码,运行正常:
var
Ps1,Ps2:PChar;
begin
Ps1 := 'ABCDEF';
GetMem(Ps2,6)
Move(Ps1[0], Ps2[0], 3);
end;
原因很简单,因为GetMem为Ps2在堆中开辟了空间
而第二段代码中,Ps1 := 'ABCDEF'由于Ps1是String类型,它的赋值操作其实是先开辟一段空间,然后把串复制到该地址空间。因此,在后面的Move操作就完全没问题。
以上分析提到了进程代码运行修改问题,可参看ReadProcessMemory WriteProcessMemory以及VirtualProtect等API函数,特别是VirtualProtect
2002.6.28 周文杰