2011-06-08 74 views
1

我真的不明白为什么这个功能不工作:Embarcadero公司Delphi和widechar:简单的功能不工作

function GetNomRepertoireTemporaire:WideString; 
var 
    PathLocal : array[0..MAX_PATH+1] of WideChar; 
begin 
    Result := ''; 
    if GetTempPath(SizeOf(PathLocal)-1, PathLocal)>0 then 
    begin 
    Result := PathLocal; 
    end; 
end; 

当我把它想:

var 
    t : wideString; 
initialization 
    t := GetNomRepertoireTemporaire; 

我等待10秒左右,然后我得到一个AV at 0x000000 address 0000000

任何人都可以解释我在做什么错了?

+0

看看德尔福给你的警告。你能列出他们吗? – Martijn 2011-06-08 13:12:13

+2

为什么widetring和widechar?为什么不是字符串和字符? – 2011-06-08 13:43:48

回答

5

你应该在你的代码中使用长度,而不是一下SizeOf:

function GetNomRepertoireTemporaire:WideString; 
var 
    PathLocal : array[0..MAX_PATH] of WideChar; 
begin 
    Result := ''; 
    if GetTempPath(Length(PathLocal), PathLocal)>0 then 
    begin 
    Result := PathLocal; 
    end; 
end; 

上面的代码假定您使用Unicode德尔福版本。由于大卫在评论中提及了你可以改变你的功能,使其与Unicode和非Unicode德尔福兼容:

function GetNomRepertoireTemporaire:String; 
var 
    PathLocal : array[0..MAX_PATH] of Char; 
begin 
    Result := ''; 
    if GetTempPath(Length(PathLocal), PathLocal)>0 then 
    begin 
    Result := PathLocal; 
    end; 
end; 

说明:GetTempPath功能用零填充它收到整个缓冲区。 OP代码设置无效缓冲区大小(实际大小的两倍),因此函数将PathLocal变量的内存置零,这会导致AV。

+0

+1是最快的,并删除了我自己的相同答案。 – 2011-06-08 13:21:39

+1

不要从缓冲区大小中减1。该文件说给它的缓冲区的大小,文档还说,返回的缓冲区是空终止的。因此,你不需要在最后保留任何东西。但是,如果你确实在最后保留一个位置,请确保设置它。另请注意,缓冲区为MAX_PATH + ** 2 **个元素。 – 2011-06-08 14:06:18

+0

@Rob:更正(删除-1)。 – kludg 2011-06-08 14:18:20

2

如果您阅读API GetTempPath的帮助文件,您会看到第一个参数是TCHAR中缓冲区的大小。 (即,缓冲区中的字符数)

现在,你正在给该函数提供缓冲区中的字节数,该字节数是字符数的两倍。

改变你的功能是这样的:

if GetTempPath(Length(PathLocal)-1, PathLocal)>0 then 
+0

↑这个答案实际上**解释**作为OP请求。 – 2011-06-08 13:51:00

+0

类,@用户。这个答案确实提到了GetTempPath被错误地调用,但它没有说明为什么会导致报告的错误。即使不需要,GetTempPath是否会覆盖缓冲区的其余部分?我觉得不太可能。即使这样做,在地址0访问内存的尝试在哪里? – 2011-06-08 14:28:41

-1

两件事情发生在我读你的源代码。

第一个是调用方法本身。我为函数GetTempPath发现的信息表明参数预期为Char(8位字符)。如果您确实需要使用宽字符字符串的临时路径,则可能必须在调用GetTempPath后将获取的路径转换为宽字符表示形式(只是猜测,因为我手边没有API文档)。

第二点是传递第二个参数。根据Delphi How To你必须提供一个指向字符数组的指针。所以对于你的例子来说应该看起来像

if GetTempPath(MAX_PATH, @PathLocal) > 0 then 

希望它有帮助。

+0

你的第二段事实上是不正确的。 GetTempPath与WinAPI中的常规一样,分别具有ANSI和Unicode版本,GetTempPathA和GetTempPathW。我们必须假定OP是一个支持Unicode的Delphi,因此调用GetTempPathW。 – 2011-06-08 14:01:34

4

虽然这并不直接回答这个问题,但最好调用内置的RTL方法IOUtils.TPath.GetTempPath

+0

你从不睡觉,是吗? +1为最短的解决方案。 – martinstoeckli 2011-06-08 14:12:02

0

您可以使用普通字符串处理此问题,并避免全部使用array of char。这是一种处理Windows API调用的好方法,因为您可以动态设置缓冲区的长度,并且SetLength函数可以与AnsiStrings以及WideStrings一起使用。

function GetNomRepertoireTemporaire: String; 
var 
    iSize: DWORD; 
begin 
    SetLength(Result, MAX_PATH); 
    iSize := GetTempPath(MAX_PATH, PChar(Result)); 
    // reduce buffer to the effectively used size. if the api call 
    // was successful, the terminating #0 is not included in iSize. 
    SetLength(Result, iSize); 
end; 

如果使用AnsiString或WideString,Delphi版本将决定。