2

내 문제는 UnicodeString이 어떻게 구현되는지 개념으로 인해 발생하지만이 문제를 해결할 수 없다.Lazarus/Delphi : 자체 할당 된 레코드 데이터 형식의 UnicodeString이 액세스 위반을 야기한다.

디스크의 디렉터리 트리를 반복적으로 검사하고 모든 파일과 하위 폴더를 표시해야하는 트리 뷰를 작성하려고합니다. 또한 각 트리 노드에 대한 추가 정보를 저장하려고합니다. TTreeNode 객체에는이 목적을위한 "데이터"속성 (포인터 유형) 만 있으므로 수동으로 메모리를 할당하고 정보를 저장하며 할당 된 포인터를 데이터 속성에 할당합니다. 내 데이터 레코드 내에 UnicodeString 필드를 사용하지 않으면 모든 것이 잘 작동하는 것처럼 보입니다.

그래서, 여기 내 사용자 정의 데이터 레코드 정의입니다 :

type 
    TFileInformation = record 
    AbsoluteFileName: UnicodeString; 
    FileSize: Int64; 
    FileAttributes: LongInt; 
    CreationTime, ModificationTime: TDateTime; 
    end; 

그리고 여기 디렉토리 recusion 내 코드입니다 : 내가 .AbsoluteFileName :=을 포함하는 행의 주석을 해제하면

const NO_ERROR = 0; 

procedure ScanDirectory(Folder: UnicodeString; Node: TTreeNode); 

var 
    Details: Pointer; 
    NewNode: TTreeNode; 
    SearchAttributes: LongInt; 
    SearchMask: UnicodeString; 
    SearchRecord: TUnicodeSearchRec; 

begin 
    if (Folder <> '') and (Folder[Length(Folder)] <> DirectorySeparator) then begin 
    Folder += DirectorySeparator; 
    end; 
    SearchMask := Folder + '*'{$IFDEF WINDOWS} + '.*'{$ENDIF}; 
    SearchAttributes := faReadOnly or faHidden or faSysFile or faDirectory or faArchive or faSymLink; 

    if FindFirst(SearchMask, SearchAttributes, SearchRecord) = NO_ERROR then begin 
    repeat 
     if ((SearchRecord.Attr and faDirectory) <> faDirectory) or 
     ((SearchRecord.Name <> '.') and (SearchRecord.Name <> '..')) then begin 
     Details := MemAlloc(SizeOf(TFileInformation)); 
     //TFileInformation(Details^).AbsoluteFileName := Folder + SearchRecord.Name; 
     TFileInformation(Details^).FileAttributes := SearchRecord.Attr; 
     TFileInformation(Details^).FileSize := SearchRecord.Size; 
     TFileInformation(Details^).CreationTime := SearchRecord.Time; 
     //TFileInformation(Details^).ModificationTime := -1; 
     if Node = nil then begin 
      NewNode := self.trvOrigin.Items.AddNode(nil, nil, ansistring(SearchRecord.Name), Details, naAdd); 
     end else begin 
      NewNode := self.trvOrigin.Items.AddNode(nil, Node, ansistring(SearchRecord.Name), Details, naAddChild); 
     end; 

     if (SearchRecord.Attr and (faDirectory or faSymLink)) = faDirectory then begin 
      // only recurse folders which are NOT SymLink: 
      ScanDirectory(Folder + SearchRecord.Name, NewNode); 
     end; 
     end; 
    until FindNext(SearchRecord) <> NO_ERROR; 
    end; 
    FindClose(SearchRecord); 
end; 

, 나는 액세스 위반을 얻을 (유닉스에서의 SIGSEGV- 예외). 현재 데비안 리눅스에서 objfpc 모드의 Lazarus를 사용하고 있습니다.하지만 Windows의 경우 델파이와 동일합니다. Treeview.Data 속성 값은 내 예제 코드의 "Details"변수에 저장됩니다. self.trvOrigin은 내 treeview 컨트롤입니다.

+0

어디에서'MemAlloc' 함수를 사용할 수 있습니까? Windows 특유의 기능이라는 것을 기억합니다. 'FreeVision'의'Memory' 단위 ('Windows' 단위 외에)에서만 찾을 수 있습니다 ... – Abelisto

+0

나사로에 포함 된 메모리 유닛을 사용합니다. –

+0

TTreeNode에서 필요로하는 추가 필드가 포함 된 파생 클래스를 만드는 것이 더 좋지 않을까요? 그렇게하면 혼자서 추가 정보를 위해 메모리를 할당하고 해제하는 것에 대해 걱정할 필요가 없습니다. 데이터 등록 정보를 사용하는 것이 더 좋은 경우는 여러 트리 노드가 동일한 추가 정보를 포함하거나이 추가 정보가 별도로 유지되는 경우입니다. – SilverWarior

답변

4

Details 레코드를 할당하면 메모리가 정의되지 않습니다.

AbsoluteFileName은 관리 형이므로 사용하기 전에 올바르게 초기화해야합니다. 당신은 할당 한 후 메모리를 삭제해야합니다

대안으로
FillChar(Details^, SizeOf(TFileInformation), #0); 

Dispose(Details)와 함께 New(Details)를 사용합니다. 레코드를 올바르게 초기화/마무리합니다.

참고 : Details은 입력 포인터, PFileInformation이어야합니다.

+0

감사합니다,이 문제가 해결되었습니다. 나는 각 필드의 할당에 의해 구조를 초기화한다고 생각하고있었습니다.하지만 당신은 옳습니다. –

+0

그 밖의 경우에는'MemAlloc' 대신'AllocMem'을 사용하십시오; Delphi에는 MemAlloc 함수가 없습니다. – kludg

+0

새 기능을 사용하지 않는 이유는 무엇입니까? 레코드를 적절하게 초기화하므로 GetMem, AllocMem 등을 대신하여 우선적으로 사용해야합니다. Dispose를 사용하여 동일한 레코드를 확보하고 포인터가 올바른 유형인지 확인하십시오. –