Następująca funkcja pobiera zaznaczony tekst w formancie Richedit
, zapisuje do TMemoryStream
wewnątrz funkcji wywołania zwrotnego, a następnie zwraca jako zwykły tekst ciąg nieprzetworzonego kodu rtf.Dlaczego ten kod kończy się niepowodzeniem podczas deklarowania TMemoryStream lokalnie, ale działa po deklaracji globalnej?
var
MS: TMemoryStream; // declared globally and works.
implementation
function GetSelectedRTFCode(RichEdit: TRichedit): string;
function RichEditCallBack(dwCookie: Longint; pbBuff: PByte;
CB: Longint; var pCB: Pointer): Longint; stdcall;
begin
MS.WriteBuffer(pbBuff^, CB);
Result := CB;
end;
var
EditStream: TEditStream;
SL: TStringList;
begin
MS := TMemoryStream.Create;
try
EditStream.dwCookie := SF_RTF or SFF_SELECTION;
EditStream.dwError := 0;
EditStream.pfnCallback := @RichEditCallBack;
Richedit.Perform(EM_StreamOut, SF_RTF or SFF_SELECTION, DWord(@EditStream));
MS.Seek(0, soBeginning);
SL := TStringList.Create;
try
SL.LoadFromStream(MS);
Result := SL.Text;
finally
SL.Free;
end;
finally
MS.Free;
end;
end;
Powyższe działa zgodnie z oczekiwaniami, bez żadnych błędów.
staram Jednak aby uniknąć globalnie deklarowanych zmiennych, jeśli to możliwe i przechowywać je lokalnie w procedurze lub funkcji, która tego potrzebuje, ale z jakiegoś powodu uznającej MS: TMemoryStream;
wewnątrz funkcji GetSelectedRTFCode
nie z Priviliged Instrukcji i błędów naruszenie zasad dostępu.
więc mając to na uwadze, a jedyną zmianą była poniżej MS: TMemoryStream;
zadeklarowana lokalnie zawiedzie:
function GetSelectedRTFCode(RichEdit: TRichedit): string;
var
MS: TMemoryStream; // declare here instead of globally but fails.
function RichEditCallBack(dwCookie: Longint; pbBuff: PByte;
CB: Longint; var pCB: Pointer): Longint; stdcall;
begin
MS.WriteBuffer(pbBuff^, CB);
Result := CB;
end;
var
EditStream: TEditStream;
SL: TStringList;
begin
MS := TMemoryStream.Create;
try
EditStream.dwCookie := SF_RTF or SFF_SELECTION;
EditStream.dwError := 0;
EditStream.pfnCallback := @RichEditCallBack;
Richedit.Perform(EM_StreamOut, SF_RTF or SFF_SELECTION, DWord(@EditStream));
MS.Seek(0, soBeginning);
SL := TStringList.Create;
try
SL.LoadFromStream(MS);
Result := SL.Text;
finally
SL.Free;
end;
finally
MS.Free;
end;
end;
Dlaczego deklarowania pamięci stream zmienną pracy na całym świecie, ale nie gdy zadeklarowana lokalnie?
To tylko System.Math potrzebne dla If Then. Nie wspominałem o tym, bo podejrzewałam, że wiesz, gdzie go znaleźć. Można to zrobić również za pomocą instrukcji if. –
Możesz również ["dodać trochę cukru"] (http://pastebin.com/udGkgwUz). Btw. wydaje się, że EMBT zbliża się do poprawnego prototypu tego wywołania zwrotnego (jeszcze nie poprawne, ale bliżej). Zmienił się od Delphi XE3. Może w XE8 będzie w końcu poprawne. – TLama
@TLama Ah, radości błędnie przetłumaczonych prototypów Win32. W tym przypadku nie ma to większego znaczenia, ponieważ jest 0, lub nie 0. –