2011-06-08 49 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版本將決定。