您现在的位置:首页 >> 基础算法 >> window基础 >> 内容

关于跨进程使用回调函数的研究,以跨进程获取Richedit中RTF流为例

时间:2011/9/3 15:38:37 点击:

  核心提示:uses RichEdit;{$WARN SYMBOL_DEPRECATED OFF}typeTRichEditStreamReader = classprivateFStream: TStream;...
uses RichEdit;

{$WARN SYMBOL_DEPRECATED OFF}

type
  TRichEditStreamReader = class
  private
    FStream: TStream;
    FHandle: THandle;
  protected
    procedure WndProc(var Message: TMessage); virtual;
  public
    constructor Create(AStream: TStream);
    destructor Destroy; override;
    property Handle: THandle read FHandle;
  end;

{ TRichEditStreamReader }

constructor TRichEditStreamReader.Create(AStream: TStream);
begin
  FStream := AStream;
  FHandle := AllocateHWnd(WndProc);
end;

destructor TRichEditStreamReader.Destroy;
begin
  DeallocateHWnd(FHandle);
  inherited;
end;

procedure TRichEditStreamReader.WndProc(var Message: TMessage);
begin
  case Message.Msg of
    WM_COPYDATA:
      begin
        if not Assigned(FStream) then Exit;
        FStream.Write(PCopyDataStruct(Message.LParam)^.lpData^,
          PCopyDataStruct(Message.LParam)^.cbData);
      end;
  end;
end;

function Process_ReadRichEditStream(
  AHandle: THandle; AStream: TStream; AFormat: Longword): Boolean;
type
  TVclApi = packed record //JMP DWORD PTR [$HHHHHHHH]
    rJmp: Word; // FF 25
    rAddress: PInteger; // API实际地址
  end;
  PVclApi = ^TVclApi;
const
  EditStreamCallBackBytes =
#$55 + //                     PUSH EBP
#$8B#$EC + //                 MOV EBP,ESP
#$83#$C4#$F4 + //             ADD ESP,$F4
#$8B#$45#$10 + //             MOV EAX,DWORD PTR [EBP+$10]
#$8B#$55#$14 + //             MOV EDX,DWORD PTR [EBP+$14]
#$89#$02 + //                 MOV DWORD PTR [EDX],EAX
#$33#$D2 + //                 XOR EDX,EDX
#$89#$55#$F4 + //             MOV DWORD PTR [EBP-$0C],EDX
#$89#$45#$F8 + //             MOV DWORD PTR [EBP-$08],EAX
#$8B#$45#$0C + //             MOV EAX,DWORD PTR [EBP+$0C]
#$89#$45#$FC + //             MOV DWORD PTR [EBP-$04],EAX
#$8D#$45#$F4 + //             LEA EAX,DWORD PTR [EBP-$0C]
#$50 + //                     PUSH EAX
#$6A#$00 + //                 PUSH $00
#$6A#$4A + //                 PUSH $4A
#$8B#$45#$08 + //             MOV EAX,DWORD PTR [EBP+$08]
#$50 + //                     PUSH EAX
#$FF#$15#$00#$00#$00#$00 + // CALL DWORD PTR [H] -- String Index:43
#$33#$C0 + //                 XOR EAX,EAX
#$8B#$E5 + //                 MOV ESP,EBP
#$5D + //                     POP EBP
#$C2#$10#$00 + //             RET $0010
#$00#$00#$00#$00 + //         Api Address -- String Index:55
#$00#$00#$00#$00 + //         _editstream : dwCookie -- String Index:59
#$00#$00#$00#$00 + //         _editstream : dwError
#$00#$00#$00#$00; //          _editstream : pfnCallback
type
  PEditStream = ^TEditStream;
var
  vEditStreamCallBack: string;
  vProcessId: DWORD;
  vProcess: THandle;
  vPointer: Pointer;
  vNumberOfBytesRead: Cardinal;
  vRichEditStreamReader: TRichEditStreamReader;
begin
  Result := False;
  if not Assigned(AStream) then Exit;
  if not IsWindow(AHandle) then Exit;
  GetWindowThreadProcessId(AHandle, @vProcessId);
  vProcess := OpenProcess(PROCESS_VM_OPERATION or PROCESS_VM_READ or
    PROCESS_VM_WRITE, False, vProcessId);
  try
    vPointer := VirtualAllocEx(vProcess, nil, 4096, MEM_RESERVE or MEM_COMMIT,
      PAGE_READWRITE);
    vRichEditStreamReader := TRichEditStreamReader.Create(AStream);
    try
      vEditStreamCallBack := EditStreamCallBackBytes;
      PInteger(@vEditStreamCallBack[43])^ := Integer(vPointer) + 55 - 1;
      PInteger(@vEditStreamCallBack[55])^ := PVclApi(@SendMessage)^.rAddress^;
      PEditStream(@vEditStreamCallBack[59])^.dwCookie := vRichEditStreamReader.Handle;
      PEditStream(@vEditStreamCallBack[59])^.pfnCallback := vPointer;
      WriteProcessMemory(vProcess, vPointer, @vEditStreamCallBack[1],
        Length(vEditStreamCallBack), vNumberOfBytesRead);
      SendMessage(AHandle, EM_STREAMOUT, AFormat, Integer(Integer(vPointer) + 59 - 1));
    finally
      vRichEditStreamReader.Free;
      VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE);
    end;
  finally
    CloseHandle(vProcess);
  end;
end; { Process_ReadRichEditStream }

procedure TForm1.Button1Click(Sender: TObject);
var
  vHandle: THandle;
  vMemoryStream: TMemoryStream;
begin
  vHandle := FindWindow('WordPadClass', nil);
  if vHandle = 0 then Exit;
  vHandle := FindWindowEx(vHandle, 0, 'RICHEDIT50W', nil);
  if vHandle = 0 then Exit;
  vMemoryStream := TMemoryStream.Create;
  try
    Process_ReadRichEditStream(vHandle, vMemoryStream, SF_RTF);
    vMemoryStream.Position := 0;
    RichEdit1.PlainText := False;
    RichEdit1.Lines.LoadFromStream(vMemoryStream);
  finally
    vMemoryStream.Free;
  end;
end;
更多详解请访问作者博客:http://blog.csdn.net/zswang/archive/2008/07/13/2645555.aspx

作者:王集鹄 来源:转载
共有评论 1相关评论
发表我的评论
  • 大名:
  • 内容:
  • 盒子文章(www.2ccc.com) © 2024 版权所有 All Rights Reserved.
  • 沪ICP备05001939号