以下函数将Richedit
控件中的选定文本写入TMemoryStream
回调函数内部,然后以纯文本字符串形式返回原始rtf代码。
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;
上述工作如预期,没有任何错误。
但是,尽可能避免全局声明的变量,并将它们保留在需要它的过程或函数的本地,但由于某些原因MS: TMemoryStream;
,在GetSelectedRTFCode
函数内部声明失败,并出现“特权指令”和“访问冲突”错误。
因此,考虑到这一点,以下在MS: TMemoryStream;
本地声明的唯一更改将失败:
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;
为什么要在全局声明内存流变量,但在本地声明时失败?
发布于 2018-05-21 14:34:42
问题是你使用嵌套函数作为回调是错误的。只要嵌套函数没有引用周围函数的任何局部变量,通过使用嵌套函数的方式实现32位编译器的机会。
但是,只要嵌套函数引用任何此类局部变量,就必须传递一个额外的隐藏参数,以便嵌套函数可以访问周围的函数堆栈帧。对于64位编译器,总是传递一个隐藏的额外参数。
你必须做的是停止使用嵌套函数进行回调。你需要将回调函数声明为具有全局范围。通过结构的dwCookie
成员传递内存流EDITSTREAM
。
// This compiles now, but the callback implementation is wrong, see below
function RichEditCallBack(dwCookie: DWORD_PTR; pbBuff: PByte;
CB: Longint; var pCB: Longint): Longint; stdcall;
var
MS: TMemoryStream;
begin
MS := TMemoryStream(dwCookie);
MS.WriteBuffer(pbBuff^, CB);
Result := CB;
end;
function GetSelectedRTFCode(RichEdit: TRichedit): string;
var
MS: TMemoryStream;
EditStream: TEditStream;
SL: TStringList;
begin
MS := TMemoryStream.Create;
try
EditStream.dwCookie := DWORD_PTR(MS);
EditStream.dwError := 0;
EditStream.pfnCallback := RichEditCallBack;
Richedit.Perform(EM_StreamOut, SF_RTF or SFF_SELECTION, LPARAM(@EditStream));
MS.Seek(0, soBeginning);
SL := TStringList.Create;
try
SL.LoadFromStream(MS);
Result := SL.Text;
finally
SL.Free;
end;
finally
MS.Free;
end;
end;
https://stackoverflow.com/questions/-100004532
复制相似问题