Einzelnen Beitrag anzeigen

Viktorii

Registriert seit: 19. Jul 2007
358 Beiträge
 
#5

Re: Thread & WaitForSingleObject - Access Violation bei

  Alt 7. Feb 2008, 11:03
Vielen Dank für den Link. Das war schon mal sehr aufschlussreich.
Okay, wo das Problem liegt habe ich nun verstanden. Auch den Lösungsansatz habe ich größtenteils verstanden, denke ich. Hab es zwar (noch) nicht komplett im Detail nachvollziehen können, aber ich dachte mir ich probiert es einmal. Und da hat sich gezeigt, dass ich es wohl doch nicht so ganz verstanden habe...

Also, es sieht jetzt folgendermaßen aus:

Delphi-Quellcode:
type
  TBulkTransferThread = class(TThread)
  private
    ...
    ...
    WriteFinishedEvent : TEvent;
    FEnumProcInst : Pointer;
    function MakeProcInstance(M: TMethod): Pointer;
    procedure CallbackFktWrite(ErrorCode : Longint; NumberOfBytesTransfered : Longint); stdcall;
  protected

  public
    constructor create(...
                       ...);
  end;


  TBulkWriteThread = class(TBulkTransferThread)
  protected
    procedure Execute; override;
  end;
  
  ...
  ...

Die Funktion MakeProcInstance habe ich einfach mal so übernommen:

Delphi-Quellcode:
function TBulkTransferThread.MakeProcInstance(M: TMethod): Pointer;
begin
  // Ausführbaren Speicher alloziieren fü 15 Byte an Code
  Result := VirtualAlloc(nil, 15, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  asm
    // MOV ECX,
    MOV BYTE PTR [EAX], $B9
    MOV ECX, M.Data
    MOV DWORD PTR [EAX+$1], ECX
    // POP EDX (bisherige Rücksprungadresse nach edx)
    MOV BYTE PTR [EAX+$5], $5A
    // PUSH ECX (self als Parameter 0 anfügen)
    MOV BYTE PTR [EAX+$6], $51
    // PUSH EDX (Rücksprungadresse zurück auf den Stack)
    MOV BYTE PTR [EAX+$7], $52
    // MOV ECX, (Adresse nach ecx laden)
    MOV BYTE PTR [EAX+$8], $B9
    MOV ECX, M.Code
    MOV DWORD PTR [EAX+$9], ECX
    // JMP ECX (Sprung an den ersten abgelegten Befehl und Methode aufrufen)
    MOV BYTE PTR [EAX+$D], $FF
    MOV BYTE PTR [EAX+$E], $E1
    // hier kein Call, ansonsten würde noch eine Rücksprungadresse auf den Stack gelegt
  end;
end;

Hier 'füge' ich nun den Self Parameter 'an':

Delphi-Quellcode:
procedure TBulkWriteThread.Execute();
var
  bRet : BOOL;
  Ret : Integer;
  Method : TMethod;

begin
  WriteFinishedEvent := TEvent.Create(nil,true,false,'WriteEvent');

  WriteFinishedEvent.ResetEvent;

  Method.Code := @TBulkTransferThread.CallbackFktWrite;
  Method.Data := Self;
  FEnumProcInst := MakeProcInstance(Method);


  bRet := USBWriteAsync(PipeHandle,
                        @USBcb,
                        HEADERSIZE,
                        FEnumProcInst);
// @CallbackFktWrite);

  Ret := WaitForSingleObject(WriteFinishedEvent.Handle, TIMEOUT_VALUE);

  ...
  ...

Wenn ich den Self Parameter nun hier zur Verfügung habe, wie komme ich dann an ihn ran?

Delphi-Quellcode:
Procedure CallbackFktWrite(ErrorCode : Longint; NumberOfBytesTransfered : Longint); stdcall;
begin
  if ErrorCode <> 0 then
  begin
    ErrorCode := GetLastError();
    MessageDlg('Error#: ' + IntToStr(ErrorCode), mtError, [mbOk], 0);
  end;

  SetEvent({??????}WriteFinishedEvent.Handle{??????});
end;

Vielleicht bringt der nächste Hinweis ja Licht in mein Dunkel.

Vielen Dank nochmals.
  Mit Zitat antworten Zitat