La seguente funzione riprende il testo selezionato in un controllo Richedit
, scrive su un TMemoryStream
all'interno di una funzione di callback e quindi restituisce come stringa di testo normale il codice rtf non elaborato.Perché questo codice ha esito negativo quando si dichiara TMemoryStream localmente ma funziona quando viene dichiarato globalmente?
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;
Quanto sopra funziona come previsto senza errori.
Tuttavia, cerco di evitare le variabili dichiarate a livello globale, quando possibile e tenerli locale alla procedura o funzione che ne ha bisogno, ma per qualche motivo dichiarando MS: TMemoryStream;
all'interno della funzione GetSelectedRTFCode
fallisce con istruzioni Priviliged e gli errori di violazione di accesso.
Quindi, con questo in mente, e l'unico cambiamento in basso stato MS: TMemoryStream;
dichiarato localmente fallisce:
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;
Perchè dovrebbe dichiarare una variabile flusso di memoria di lavoro a livello globale, ma fallire quando dichiarato localmente?
È solo System.Math necessario per IfThen. Non l'ho menzionato perché sospettavo che tu sapessi dove trovarlo. Può essere fatto anche con una dichiarazione if. –
Puoi anche ['aggiungere un po 'di zucchero'] (http://pastebin.com/udGkgwUz). Btw. sembra che EMBT si stia avvicinando al prototipo corretto di quella richiamata (non ancora corretta, ma più vicina). È cambiato da Delphi XE3. Forse in XE8 sarà finalmente corretto. – TLama
@TLama Ah, le gioie dei prototipi Win32 tradotti male. In questo caso non importa tanto perché è 0, o non 0. –