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 周文杰
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 周文杰
解决方案 »
免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货