首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么此代码在本地声明TMemoryStream时失败,但在全局声明时工作?

为什么此代码在本地声明TMemoryStream时失败,但在全局声明时工作?
EN

Stack Overflow用户
提问于 2018-05-21 04:40:34
回答 1查看 0关注 0票数 0

以下函数将Richedit控件中的选定文本写入TMemoryStream回调函数内部,然后以纯文本字符串形式返回原始rtf代码。

代码语言:javascript
复制
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;本地声明的唯一更改将失败:

代码语言:javascript
复制
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;

为什么要在全局声明内存流变量,但在本地声明时失败?

EN

回答 1

Stack Overflow用户

发布于 2018-05-21 14:34:42

问题是你使用嵌套函数作为回调是错误的。只要嵌套函数没有引用周围函数的任何局部变量,通过使用嵌套函数的方式实现32位编译器的机会。

但是,只要嵌套函数引用任何此类局部变量,就必须传递一个额外的隐藏参数,以便嵌套函数可以访问周围的函数堆栈帧。对于64位编译器,总是传递一个隐藏的额外参数。

你必须做的是停止使用嵌套函数进行回调。你需要将回调函数声明为具有全局范围。通过结构的dwCookie成员传递内存流EDITSTREAM

代码语言:javascript
复制
// 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;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100004532

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档