如何得到其他程序的Richedit中的RTF数据?

解决方案 »

  1.   

    具体问题具体分析,每个程序RICHEDIT用的方法不一样.
      

  2.   

    跨进程获得RichEdit Text参考:
    uses RichEdit;function Process_ReadRichEditText(AHandle: THandle): WideString;
    var
      vGetTextEx: GETTEXTEX;
      vGetTextLengthEx: GETTEXTLENGTHEX;
      L: Integer;  vProcessId: DWORD;
      vProcess: THandle;
      vPointer: Pointer;
      vNumberOfBytesRead: Cardinal;
    begin
      Result := '';
      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);
        try
          vGetTextLengthEx.flags := GTL_DEFAULT;
          vGetTextLengthEx.codepage := 1200; // Unicode
          WriteProcessMemory(vProcess, vPointer, @vGetTextLengthEx,
            SizeOf(vGetTextLengthEx), vNumberOfBytesRead);
          L := SendMessage(AHandle, EM_GETTEXTLENGTHEX, Integer(vPointer), 0);
        finally
          VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE);
        end;
        if L <= 0 then Exit;
        vPointer := VirtualAllocEx(vProcess, nil, SizeOf(vGetTextEx) + L * 2 + 2,
          MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
        try
          SetLength(Result, L);
          vGetTextEx.cb := L * 2 + 2; // 加上结束符号
          vGetTextEx.flags := GT_DEFAULT;
          vGetTextEx.codepage := 1200; // Unicode
          vGetTextEx.lpDefaultChar := nil;
          vGetTextEx.lpUsedDefChar := nil;
          WriteProcessMemory(vProcess, vPointer, @vGetTextEx,
            SizeOf(vGetTextEx), vNumberOfBytesRead);
          SendMessage(AHandle, EM_GETTEXTEX, Integer(vPointer),
            Integer(vPointer) + SizeOf(vGetTextEx));
          ReadProcessMemory(vProcess, Pointer(Integer(vPointer) + SizeOf(vGetTextEx)),
            @Result[1], L * 2, vNumberOfBytesRead);
        finally
          VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE);
        end;
      finally
        CloseHandle(vProcess);
      end;
    end; { Process_ReadRichEditText }调试代码(环境是XP):
    procedure TForm1.Button1Click(Sender: TObject);
    var
      vHandle: THandle;
    begin
      vHandle := FindWindow('WordPadClass', nil);
      if vHandle = 0 then Exit;
      vHandle := FindWindowEx(vHandle, 0, 'RICHEDIT50W', nil);
      if vHandle = 0 then Exit;
      Memo1.Text := Process_ReadRichEditText(vHandle);
    end;获取RTF就比较麻烦楼主现身再说
      

  3.   

    补充下,大师这个代码可以在vista sp1下工作
      

  4.   

    参考如下代码:
    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;
      

  5.   

    研究过程参考我写的博文:关于跨进程使用回调函数的研究:以跨进程获取Richedit中RTF流为例。记得要结贴。
      

  6.   

    老是说[DCC Error] Unit3.pas(28): E2004 Identifier redeclared: 'TRichEditStreamReader.Create'
      

  7.   

    囧,你把Unit3.pas帖出来看看。unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ComCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        RichEdit1: TRichEdit;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}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;end.
      

  8.   

    确实能抓到rtf文本了,但图片还是不行...
    大师,您要深入研究,还是让我现在散分?
      

  9.   

    大师果然是大师,其实捕获的rtf数据流已经包含所有数据了,其他就是用什么方法显示了,应该是另一个问题了,多谢!散分!再次感谢!
      

  10.   

    这么说吧,我用rxrichedit作显示,获取qq聊天窗口文本(窗口ID 380  类名 RichEdit20A),获取的rtf文本中的gif在rxrichedit中可以正常显示动画,但是qq窗口中就不行了,就不动了,定格在第一帧,但也不是必然,我算了下,大概一半多的几率出现这个问题
      

  11.   

    试了一下,确实有这样的情况,特别是没有显示出来的GIF更容易静止掉。估计是转化为RTF流的时候,优化资源出的问题。这个已经超出我的控制范围楼主继续研究吧我闪了
      

  12.   

    大师不帮忙了,郁闷ing......................
      

  13.   

    ^^ 徐诶下挨踢网 【中文IT技术社区】【主页地址】http://www.aitic.net
    【论坛入口】http://www.aitic.net/bbs
    我们的目标是:做开源的中文IT技术社区,为IT人提供最好的技术交流平台,发布最全面的IT技术资料!
    我们的口号是:让IT人从此不挨踢!