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.