用pchar就出错,用string就没事,为什么?(100分)

  • 主题发起人 主题发起人 wddelphi
  • 开始时间 开始时间
W

wddelphi

Unregistered / Unconfirmed
GUEST, unregistred user!
procedure TFrm_Main.Button2Click(Sender: TObject);
var
BI:browseinfo;
IDLt:pointer;
str1:pchar;
begin
BI.hWndOwner := Handle
BI.iImage :=0;
BI.lParam :=0;
BI.lpfn :=nil;
BI.lpszTitle :='请选择目录:';
BI.ulFlags :=BIF_RETURNONLYFSDIRS
IDLt := SHBrowseForFolder(BI);
if assigned(IDLt) then
Begin
SHGetPathFromIDList(IDLt,str1);
Edt_Dir.Text :=str1;
end;
end;

以上程序运行完会出错,但值也能得到;

procedure TFrm_Main.Button2Click(Sender: TObject);
var
BI:browseinfo;
IDLt:pointer;
str1:string;
begin
BI.hWndOwner := Handle
BI.iImage :=0;
BI.lParam :=0;
BI.lpfn :=nil;
BI.lpszTitle :='请选择目录:';
BI.ulFlags :=BIF_RETURNONLYFSDIRS
IDLt := SHBrowseForFolder(BI);
if assigned(IDLt) then
Begin
setlength(str1,255);
SHGetPathFromIDList(IDLt,pchar(str1));
Edt_Dir.Text :=str1;
end;
end;
以上程序不会出错,但得到的目录长度是固定的,不灵活。

哪位高手帮忙解答一下,区区100两奉上,谢谢了!
 
GetMem(Str1,255);
FreeMem(Str1);
需要申请空间的。
 
还有,你的目录长度,最多也就255个字节,无所谓的,固定长度。
 
PChar 要分配内存的
 
谢谢yzhshi,你的回答是针对用string的吗?我用了setlength(str1,255);,但这不是
我要的,因为这样选择的目录的长度必须在申请的长度内,而用pchar这没有这样的限制,
但是出错……
你能回答我怎样用pchar才不会出错吗?因为我跟踪程序,它是在end;之后出错的。
 
PChar 要分配内存吗?
procedure TFrm_Main.Button3Click(Sender: TObject);
var
aaa:pchar;
begin
aaa:='1235647';
ShowMessage(aaa);
edt_dir.Text :=aaa;
end;

不会出错~
 
能,在Windows下,目录长度最长为255,包括多级目录,你可以实验一下。
所以没有这个担心。
我的那个分配内存应该可以的。(不过在我的计算机上蹦叉,呵呵,我的计算机出问题了。)
procedure TForm1.Button1Click(Sender: TObject);
var
BI: browseinfo;
IDLt: pointer;
str1: pChar;
begin
GetMem(Str1, 255);
BI.hWndOwner := Handle;
BI.iImage := 0;
BI.lParam := 0;
BI.lpfn := nil;
BI.lpszTitle := '请选择目录:';
BI.ulFlags := BIF_RETURNONLYFSDIRS;
IDLt := SHBrowseForFolder(BI);
if assigned(IDLt) then
Begin
SHGetPathFromIDList(IDLt, pChar(str1));
ShowMessage(str1);
end;
FreeMem(Str1);
end;
 
你的那个aaa:='aaa'
基本就相当与赋值了,它好像还可以分配空间的。
但是真正使用的时候最好先分配空间,否则很容易出 bug。
 
pchar 用在API函数中必须小心使用,注意分配内存!
 
但是yzhshi,我试了一下,windows的路径长度能超过255的,我用的是win2000 professional,
其实我又试了一下,用pchar也不一定出错,只要路径长度小于等于15字节,奇怪吧?

其实我贴出来的程序肯定出错,如果像下面这样写,就能在路径小于等于15字节时不出错,
而且目录打开的窗口也有略微不同,请仔细看:

一:
procedure TFrm_Main.Button2Click(Sender: TObject);
var
BI:browseinfo;
IDLt:pointer;
str1:pchar;
str2:string;
begin
BI.hWndOwner := Handle
BI.iImage :=0;
BI.lParam :=0;
BI.lpfn :=nil;
BI.lpszTitle :='请选择目录:';
BI.ulFlags :=BIF_RETURNONLYFSDIRS
IDLt := SHBrowseForFolder(BI);
if assigned(IDLt) then
Begin
setlength(str2,18);//随便多少
SHGetPathFromIDList(IDLt,str1);
Edt_Dir.Text :=str1;
end;
end;

二:
procedure TFrm_Main.Button2Click(Sender: TObject);
var
BI:browseinfo;
IDLt:pointer;
str1:pchar;
begin
BI.hWndOwner := Handle
BI.iImage :=0;
BI.lParam :=0;
BI.lpfn :=nil;
BI.lpszTitle :='请选择目录:';
BI.ulFlags :=BIF_RETURNONLYFSDIRS
IDLt := SHBrowseForFolder(BI);
if assigned(IDLt) then
Begin
SHGetPathFromIDList(IDLt,str1);
Edt_Dir.Text :=str1;
end;
end;

以上两段程序,仅仅区别于一个变量(而且没有用到),而打开的窗口及运行的正确性
却截然不同,真奇怪,请运行一下看看吧!
 
就是申请内存的原因呀。没有申请内存,程序可能使用到不可预知的内存。
所以产生问题的可能性很大,但是并不是说一定产生问题。
所以很可能出现这个问题。
对于pChar,必须申请内存。
还有,你出这个问题,很可能是因为Str1正好使用了Str2的内存,所以没有出错(当然,这句话很不负责任的吆)
 
“很可能是因为Str1正好使用了Str2的内存”这个说法应该是错的,因为,即便我将str2
setlength为200,str1的内容仍不能超过15个字节。

多了个str2,再setlength,打开目录的窗口的初试选定的地方就从“桌面”变为了
“我的电脑”,这应该不是内存的问题吧,因为setlength根本还没运行到,我脑袋都快
抓破了,到不是急着用这个,而是想不通,没头绪,痛苦!

快救救我吧!
 
而且,只要路径长度小于等于15字节就不出错,这似乎是一定的,没有什么变数。
 
呵呵,就是申请内存的问题,我感觉该说的都说完了呀。。。
 
yzhshi,我试了你的程序:

procedure TForm1.Button1Click(Sender: TObject);
var
BI: browseinfo;
IDLt: pointer;
str1: pChar;
begin
GetMem(Str1, 255);
BI.hWndOwner := Handle;
BI.iImage := 0;
BI.lParam := 0;
BI.lpfn := nil;
BI.lpszTitle := '请选择目录:';
BI.ulFlags := BIF_RETURNONLYFSDIRS;
IDLt := SHBrowseForFolder(BI);
if assigned(IDLt) then
Begin
SHGetPathFromIDList(IDLt, pChar(str1));
ShowMessage(str1);
end;
FreeMem(Str1);
end;

其运行结果和这段一样:
procedure TFrm_Main.Button2Click(Sender: TObject);
var
BI:browseinfo;
IDLt:pointer;
str1:pchar;
begin
BI.hWndOwner := Handle
BI.iImage :=0;
BI.lParam :=0;
BI.lpfn :=nil;
BI.lpszTitle :='请选择目录:';
BI.ulFlags :=BIF_RETURNONLYFSDIRS
IDLt := SHBrowseForFolder(BI);
if assigned(IDLt) then
Begin
SHGetPathFromIDList(IDLt,str1);
Edt_Dir.Text :=str1;
end;
end;

报错是user32.dll什么的错误!
 
創建或使用pchar最好用專用的str開頭的函數,而不要用 getmem這一類pascal的函數
不然死了你都不知道怎么死的,我可是深受其害的
如下

StrAlloc Allocates a character buffer of a given size on the heap.
StrBufSize Returns the size of a character buffer allocated using StrAlloc or StrNew.
StrCat Concatenates two strings.
StrComp Compares two strings.
StrCopy Copies a string.
StrDispose Disposes a character buffer allocated using StrAlloc or StrNew.
StrECopy Copies a string and returns a pointer to the end of the string.
StrEnd Returns a pointer to the end of a string.
StrFmt Formats one or more values into a string.
StrIComp Compares two strings without case sensitivity.
StrLCat Concatenates two strings with a given maximum length of the resulting string.
StrLComp Compares two strings for a given maximum length.
StrLCopy Copies a string up to a given maximum length.
StrLen Returns the length of a string.
StrLFmt Formats one or more values into a string with a given maximum length.
StrLIComp Compares two strings for a given maximum length without case sensitivity.
StrLower Converts a string to lowercase.
StrMove Moves a block of characters from one string to another.
StrNew Allocates a string on the heap.
StrPCopy Copies a Pascal string to a null-terminated string.
StrPLCopy Copies a Pascal string to a null-terminated string with a given maximum length.
StrPos Returns a pointer to the first occurrence of a given substring within a string.
StrRScan Returns a pointer to the last occurrence of a given character within a string.
StrScan Returns a pointer to the first occurrence of a given character within a string.
StrUpper Converts a string to uppercase.

 
GetMem(Str1, 255)
改为 Str1 := StrAlloc(MAX_PATH);
FreeMem(Str1)
改为 StrDispose(str1);
另外SHGetPathFromIDList(IDLt,str1);的返回值如果根目录为C:/,否则为C:/TEMP
 
yzhshi和lqy,因为目录的长度可能超过255字节的(我只是想做得灵活点),我想用pchar,
怎样才能不让它出错?不会要我用try……吧! :~ (
 
老凶pchar也就好象c里的char *,你说该咋办?????!!!!!!!!!!!!!!
 
為你試過了﹐還搞得我死了一次機呢

procedure TForm1.Button1Click(Sender: TObject);
var
BI:browseinfo;
IDLt:pointer;
str1:pchar;
begin
fillchar(bi,sizeof(browseinfo),0);
BI.hWndOwner := Handle
BI.iImage :=0;
BI.lParam :=0;
BI.lpfn :=nil;
BI.lpszTitle :='aaaa:';
BI.ulFlags :=BIF_RETURNONLYFSDIRS
IDLt := SHBrowseForFolder(BI);
if assigned(IDLt) then
Begin
str1:=stralloc(MAX_PATH);
SHGetPathFromIDList(IDLt,str1);
Edt_Dir.Text:=str1;
strdispose(str1);
end;
end;
 
后退
顶部