初学winapi问题一:在转换pchar为string时,为乱码或出错?(50分)

F

filter

Unregistered / Unconfirmed
GUEST, unregistred user!
各位朋友好,我初学WINAPI,遇到了些难以解决的问题。程序如下
procedure TForm1.Button1Click(Sender: TObject);
var
dl:word;
fromcaption:pchar;
data:string;
begin
dl:= GetWindowText(Form1.Handle,fromcaption,128);
data:=strpas(fromcaption);
Button1.Caption:=data;
end;
我知道pchar与string的区别在于一个有'/0',一个没有。程序中data正确生成为form1,
但在button1.caption为乱码?我如换成data:=string(fromcaption);时,那么Button1.Caption:=data;
出错。
为什么,请指教
 
你的 fromcaption:pchar;
没有分配内存...
 
pchar变量可以直接赋给string变量
 
看看下面这段,完整的到http://wolfsoft.nugoo.com 下载《Pascal精要》
Delphi 字符串与 Windows PChar字符串
长字符串为零终止串,这意味着长字符串完全与Windows使用的C语言零终止串兼容,这给长字符串使用带来了便利。一个零终止串是一个字符序列,该序列以一个零字节(或null)结尾。零终止串在Delphi中可用下标从零开始的字符数组表示,C语言就是用这种数组类型定义字符串,因此零终止字符数组在Windows API 函数(基于C语言)中很常见。由于Pascal长字符串与C语言的零终止字符串完全兼容,因此当需要把字符串传递给Windows API 函数时,你可以直接把长字符串映射为PChar 类型。
下例把一个窗体的标题拷贝给PChar 字符串(用API 函数GetWindowText),然后再把它拷贝给按钮的Caption 属性,代码如下:
procedure TForm1.Button1Click (Sender: TObject);
var
S1: String;
begin
SetLength (S1, 100);
GetWindowText (Handle, PChar (S1), Length (S1));
Button1.Caption := S1;
end;
你可以在例LongStr 中找到这段代码。注意:代码中用SetLength函数为字符串分配内存,假如内存分配失败,那么程序就会崩溃;如果你直接用PChar 类型传递值(而不是象以以上代码那样接受一个值),那么代码会很简单,因为不需要定义临时字符串,也不需要初始化串。下面代码把一个Label(标签)控件的Caption 属性作为参数传递给了API函数,只需要简单地把属性值映射为PChar类型:
SetWindowText (Handle, PChar (Label1.Caption));
当需要把WideString 映射为Windows兼容类型时,你必须用PWideChar 代替PChar进行转换,WideString常用于OLE和 COM 程序。
刚才展现了长字符串的优点,现在谈谈它的弊端。当你把长字符串转换为PChar 类型时可能会引发一些问题,问题根本在于:转换以后字符串及其内容将由你来负责,Delphi 不再管了。现在把上面Button1Click代码稍作修改:
procedure TForm1.Button2Click(Sender: TObject);
var
S1: String;
begin
SetLength (S1, 100);
GetWindowText (Handle, PChar (S1), Length (S1));
S1 := S1 + ' is the title';
// this won't work
Button1.Caption := S1;
end;
程序编译通过,但执行结果会令你惊讶,因为按钮的标题并没变,所加的常量字符串没有添加到按钮标题中。问题原因是Windows写字符串时(在GetWindowText API调用中),Windows 没有正确设置Pascal 长字符串的长度。Delphi 仍可以输出该字符串,并能通过零终止符判断字符串何时结束,但是如果你在零终止符后添加更多的字符,那么这些字符将被忽略。
怎么解决这个问题呢?解决方法是告诉系统把GetWindowText API函数返回的字符串再转换成Pascal字符串。然而,如果你用以下代码:
S1 := String (S1);
Delphi 系统将不予理睬,因为把一种类型转换为它自己的类型是无用的操作。为获得正确的Pascal 长字符串,需要你把字符串重新映射为一个PChar 字符串,然后让Delphi 再把它转回到字符串:
S1 := String (PChar (S1));
实际上,你可以跳过字符串转换(S1 := PChar (S1));, 因为在Delphi中Pchar转换到string是自动执行的,最终代码如下:
procedure TForm1.Button3Click(Sender: TObject);
var
S1: String;
begin
SetLength (S1, 100);
GetWindowText (Handle, PChar (S1), Length (S1));
S1 := String (PChar (S1));
S1 := S1 + ' is the title';
Button3.Caption := S1;
end;
另一个办法是用PChar 字符串的长度重新设定Delphi 字符串长度,可以这样写:
SetLength (S1, StrLen (PChar (S1)));
在例LongStr中你可以看到三种方法的结果,分别由三个按钮执行。如果只想访问窗体标题,仅需要用到窗体对象本身的Caption 属性,没有必要写这段迷糊人的代码,这段代码只是用来说明字符串转换问题。当调用Windows API 函数时会遇到这种实际问题,那时你就不得不考虑这一复杂情况了。
 
procedure TForm1.Button2Click(Sender: TObject);
var
dl:word;
fromcaption:array[0..127] of char;
data:string;
begin
dl:= GetWindowText(Form1.Handle,fromcaption,128);
data:=string(fromcaption);
Button1.Caption:=data;
end;
 
可我的程序为什么会错误呢?不理解
 
PChar是一个指针, 使用的时候要先分配内存, 不然它是无效的..
 
procedure TForm1.Button1Click(Sender: TObject);
var
dl:word;
fromcaption:pchar;
data:string;
begin
fromcaption:=allocmem(255);
dl:= GetWindowText(Form1.Handle,fromcaption,128);
data:=strpas(fromcaption);
freemem(fromcaption,255);
Button1.Caption:=data;
end;
 
谢谢各位的帮助
 
顶部