MEGA Search
20.3 Million


Sign Up
From: Grendel  
Subject: Clipboard (sorry, a bit long, but I wanted to get all the de
NewsGroup: borland.public.delphi.language.objectpascal
Date Posted: 10-Feb-2003 at 9:17:23 PST
Hi,

I have written an application that sends text to another application.  I
test this with Wordpad, but it works with IE and others.

The way I have done this at the moment is to loop through the text and send
the relevant keystrokes to the other application.  This works very well and
I have no problems with it.

However, I would like to speed it up slightly and use the clipboard.  I can
get the text into the clipboard, but I have a problem when pasting from it :

I have multiple lines of text that I want to send, so do them one at a time.
I paste what I want into a RichEdit box and then use
RichEdit1.CopytoClipboard.

I then use a kebd_event with CTRL+V (tried SendMessage and PostMessage with
a WM_PASTE but that doesn't seem to do anything).

The basics of the code are :

For each line of text :
Get text to send
Clear RichEdit
Paste text into RichEdit
Select text in RichEdit
RichEdit.CopyToClipboard
Call procedure to send the keyboard event
// end of loop

As you can see, the keyboard event happens once per line of text.  However,
when I do the above, I just get the last line of text pasted as many times
as I loop through.

e.g. I have 3 lines :
line 1
line 2
line 3

But all I get in my called application is line 3, three times (i.e. it waits
until the whole process has finished then pastes the last clipboard text).

So, two questions :
1) Why is it waiting to do the pasting, even though it's called in each loop
pass (and I'm using Application.ProcessMessages).
2) Is there a way to determine how many items are in the clipboard and
select which one to paste, as you can see in Word?

Thanks,

Gareth.






From: Grendel  
Subject: Re: Clipboard (sorry, a bit long, but I wanted to get all th
NewsGroup: borland.public.delphi.language.objectpascal
Date Posted: 11-Feb-2003 at 13:4:51 PST
Thanks for this.

Unfortunately, I was testing with Wordpad and everything was going along
fine, the output was exactly what I wanted.

However, when using the application in the way it was written for (to paste
multilple commands into a browser window) the CRLFs are not being processed.
So if I have four lines, they just sit there altogether waiting for a
keypress.

If I send them one line at a time using CTRL+V then they are ok.

Hmm, strange.

Gareth.



"wim baert"  wrote in message
news:3e48ba46@newsgroups.borland.com...
> Hi,
>
> here is some code I use to send data to the clipboard.
> perhaps you can use it
>
> unit ClipboardFun;
>
> interface
>
> uses classes, sysutils, clipbrd, windows;
>
> procedure CopyStreamToClipboard( fmt: Cardinal; S: TStream );
> procedure CopyClipboardToStream(fmt: Cardinal; S: TStream);
>
>
> implementation
>
>
> procedure CopyStreamToClipboard( fmt: Cardinal; S: TStream );
> var
>   hMem: THandle;
>   pMem: Pointer;
> begin
>   hMem := Clipboard.GetAsHandle(fmt);
>   if hMem <> 0 then begin
>     GlobalFree( hMem );
>   end;
>   ClipBoard.Open;
>   try
>     Clipboard.Clear;
>   finally
>     Clipboard.Close;
>   end;
>   { Rewind stream position to start }
>   S.Position := 0;
>   { Allocate a global memory block the size of the stream data }
>   hMem := GlobalAlloc(GHND or GMEM_DDESHARE, S.Size);
>   if hMem <> 0 then begin
>     { Succeeded, lock the memory handle to get a pointer to the
>       memory. }
>     pMem := GlobalLock(hMem);
>     if pMem <> nil then begin
>       { Succeeded, now read the stream contents into the memory
>         the pointer points at. }
>       try
>         S.Read( pMem^, S.Size);
>         { Rewind stream again, caller may be confused if the stream
>           position is left at the end. }
>         S.Position := 0;
>       finally
>         { Unlock the memory block. }
>         GlobalUnlock(hMem);
>       end;
>
>       { Open clipboard and put the block into it. The way the
>         Delphi clipboard object is written this will clear the
>         clipboard first. Make sure the clipboard is closed even
>         in case of an exception. If left open it would become
>         unusable for other apps. }
>       Clipboard.Open;
>       try
>         Clipboard.SetAsHandle(fmt, hMem);
>       finally
>         Clipboard.Close;
>       end;
>     end else Begin
>       { Could not lock the memory block, so free it again and
>         raise an out of memory exception. }
>       GlobalFree( hMem );
>       OutOfMemoryError;
>     end;
>   end else begin
>     { Failed to allocate the memory block, raise exception. }
>     OutOfMemoryError;
>   end;
> End; { CopyStreamToClipboard }
>
> procedure CopyClipboardToStream(fmt: Cardinal; S: TStream);
> var
>   hMem: THandle;
>   pMem: Pointer;
> begin
> //  hMem := 0;
> //  pMem := nil;
>   hMem := Clipboard.GetAsHandle(fmt);
>   try
>     if hMem <> 0 then begin
>       pMem := GlobalLock(hMem);
>       if pMem <> nil then begin
>         try
>           S.Write(pMem^, GlobalSize(hMem));
>           S.Position := 0;
>         finally
>           GlobalUnlock(hMem);
>         end;
>       end else begin
>         raise Exception.Create(
>           'CopyStreamFromClipboard: could not lock global handle '+
>           'obtained from clipboard!');
>       end;
>     end;
>   finally
>   end;
> end;
>
> end.
>
> In the main program i put the following code (stream, data and datalength
> have to be declared... :
>
> stream:=tmemorystream.create; //stream is of type TMemoryStream
> try
>  data:='hello'+#00; {data = a string, you have to null-terminated it
before
> sendig it to the clipboard}
>  datalength:=length(data); //datalength = an integer
>  stream.write(data[1],datalenght);
>  stream.seek(0,soFromBeginning);
>  CopyStreamToClipBoard(CF_TEXT,stream)
> finally
>  stream.free
> end
>
>
>
>
>
> "Grendel"  schreef in bericht
> news:3e476e1f$1@newsgroups.borland.com...
> > Hi,
> >
> > I have written an application that sends text to another application.  I
> > test this with Wordpad, but it works with IE and others.
> >
> > The way I have done this at the moment is to loop through the text and
> send
> > the relevant keystrokes to the other application.  This works very well
> and
> > I have no problems with it.
> >
> > However, I would like to speed it up slightly and use the clipboard.  I
> can
> > get the text into the clipboard, but I have a problem when pasting from
it
> :
> >
> > I have multiple lines of text that I want to send, so do them one at a
> time.
> > I paste what I want into a RichEdit box and then use
> > RichEdit1.CopytoClipboard.
> >
> > I then use a kebd_event with CTRL+V (tried SendMessage and PostMessage
> with
> > a WM_PASTE but that doesn't seem to do anything).
> >
> > The basics of the code are :
> >
> > For each line of text :
> > Get text to send
> > Clear RichEdit
> > Paste text into RichEdit
> > Select text in RichEdit
> > RichEdit.CopyToClipboard
> > Call procedure to send the keyboard event
> > // end of loop
> >
> > As you can see, the keyboard event happens once per line of text.
> However,
> > when I do the above, I just get the last line of text pasted as many
times
> > as I loop through.
> >
> > e.g. I have 3 lines :
> > line 1
> > line 2
> > line 3
> >
> > But all I get in my called application is line 3, three times (i.e. it
> waits
> > until the whole process has finished then pastes the last clipboard
text).
> >
> > So, two questions :
> > 1) Why is it waiting to do the pasting, even though it's called in each
> loop
> > pass (and I'm using Application.ProcessMessages).
> > 2) Is there a way to determine how many items are in the clipboard and
> > select which one to paste, as you can see in Word?
> >
> > Thanks,
> >
> > Gareth.
> >
> >
> >
> >
> >
>
>



From: wim baert  
Subject: Re: Clipboard (sorry, a bit long, but I wanted to get all th
NewsGroup: borland.public.delphi.language.objectpascal
Date Posted: 11-Feb-2003 at 9:54:32 PST
Hi,

here is some code I use to send data to the clipboard.
perhaps you can use it

unit ClipboardFun;

interface

uses classes, sysutils, clipbrd, windows;

procedure CopyStreamToClipboard( fmt: Cardinal; S: TStream );
procedure CopyClipboardToStream(fmt: Cardinal; S: TStream);


implementation


procedure CopyStreamToClipboard( fmt: Cardinal; S: TStream );
var
  hMem: THandle;
  pMem: Pointer;
begin
  hMem := Clipboard.GetAsHandle(fmt);
  if hMem <> 0 then begin
    GlobalFree( hMem );
  end;
  ClipBoard.Open;
  try
    Clipboard.Clear;
  finally
    Clipboard.Close;
  end;
  { Rewind stream position to start }
  S.Position := 0;
  { Allocate a global memory block the size of the stream data }
  hMem := GlobalAlloc(GHND or GMEM_DDESHARE, S.Size);
  if hMem <> 0 then begin
    { Succeeded, lock the memory handle to get a pointer to the
      memory. }
    pMem := GlobalLock(hMem);
    if pMem <> nil then begin
      { Succeeded, now read the stream contents into the memory
        the pointer points at. }
      try
        S.Read( pMem^, S.Size);
        { Rewind stream again, caller may be confused if the stream
          position is left at the end. }
        S.Position := 0;
      finally
        { Unlock the memory block. }
        GlobalUnlock(hMem);
      end;

      { Open clipboard and put the block into it. The way the
        Delphi clipboard object is written this will clear the
        clipboard first. Make sure the clipboard is closed even
        in case of an exception. If left open it would become
        unusable for other apps. }
      Clipboard.Open;
      try
        Clipboard.SetAsHandle(fmt, hMem);
      finally
        Clipboard.Close;
      end;
    end else Begin
      { Could not lock the memory block, so free it again and
        raise an out of memory exception. }
      GlobalFree( hMem );
      OutOfMemoryError;
    end;
  end else begin
    { Failed to allocate the memory block, raise exception. }
    OutOfMemoryError;
  end;
End; { CopyStreamToClipboard }

procedure CopyClipboardToStream(fmt: Cardinal; S: TStream);
var
  hMem: THandle;
  pMem: Pointer;
begin
//  hMem := 0;
//  pMem := nil;
  hMem := Clipboard.GetAsHandle(fmt);
  try
    if hMem <> 0 then begin
      pMem := GlobalLock(hMem);
      if pMem <> nil then begin
        try
          S.Write(pMem^, GlobalSize(hMem));
          S.Position := 0;
        finally
          GlobalUnlock(hMem);
        end;
      end else begin
        raise Exception.Create(
          'CopyStreamFromClipboard: could not lock global handle '+
          'obtained from clipboard!');
      end;
    end;
  finally
  end;
end;

end.

In the main program i put the following code (stream, data and datalength
have to be declared... :

stream:=tmemorystream.create; //stream is of type TMemoryStream
try
 data:='hello'+#00; {data = a string, you have to null-terminated it before
sendig it to the clipboard}
 datalength:=length(data); //datalength = an integer
 stream.write(data[1],datalenght);
 stream.seek(0,soFromBeginning);
 CopyStreamToClipBoard(CF_TEXT,stream)
finally
 stream.free
end





"Grendel"  schreef in bericht
news:3e476e1f$1@newsgroups.borland.com...
> Hi,
>
> I have written an application that sends text to another application.  I
> test this with Wordpad, but it works with IE and others.
>
> The way I have done this at the moment is to loop through the text and
send
> the relevant keystrokes to the other application.  This works very well
and
> I have no problems with it.
>
> However, I would like to speed it up slightly and use the clipboard.  I
can
> get the text into the clipboard, but I have a problem when pasting from it
:
>
> I have multiple lines of text that I want to send, so do them one at a
time.
> I paste what I want into a RichEdit box and then use
> RichEdit1.CopytoClipboard.
>
> I then use a kebd_event with CTRL+V (tried SendMessage and PostMessage
with
> a WM_PASTE but that doesn't seem to do anything).
>
> The basics of the code are :
>
> For each line of text :
> Get text to send
> Clear RichEdit
> Paste text into RichEdit
> Select text in RichEdit
> RichEdit.CopyToClipboard
> Call procedure to send the keyboard event
> // end of loop
>
> As you can see, the keyboard event happens once per line of text.
However,
> when I do the above, I just get the last line of text pasted as many times
> as I loop through.
>
> e.g. I have 3 lines :
> line 1
> line 2
> line 3
>
> But all I get in my called application is line 3, three times (i.e. it
waits
> until the whole process has finished then pastes the last clipboard text).
>
> So, two questions :
> 1) Why is it waiting to do the pasting, even though it's called in each
loop
> pass (and I'm using Application.ProcessMessages).
> 2) Is there a way to determine how many items are in the clipboard and
> select which one to paste, as you can see in Word?
>
> Thanks,
>
> Gareth.
>
>
>
>
>



From: Grendel  
Subject: Re: Clipboard (sorry, a bit long, but I wanted to get all th
NewsGroup: borland.public.delphi.language.objectpascal
Date Posted: 10-Feb-2003 at 15:38:44 PST
Thanks for the reply David.

I am doing them one at a time as it splits them up nicely.  I was actually
pasting single characters at a time and going round a loop (after insterting
#13#10 at the end of each line).  I'll try doing it all in one go with CRLFs
in and see if that helps.

I tried using WM_Paste after getting the handle of the target window (was
testing with WordPad) and making sure I brought it to the front, but still
no joy.  As you say, I'm probably better off with CTRL+V as it works and
does the same thing anyway.

I experimented with some delays and got it working with a sleep(1)!!!
Bizarre, but true.

I had a feeling Word was grabbing the clipboard itself, but wanted to just
check.

Hopefully it will work with one big block, so will not be such a problem.

Thanks again,

Gareth.



"David Knaack"  wrote in message
news:3e47ba8f$1@newsgroups.borland.com...
> "Grendel"  wrote in message
> news:3e476e1f$1@newsgroups.borland.com...
> > I have multiple lines of text that I want to send, so do them one at a
> time.
> > I paste what I want into a RichEdit box and then use
> > RichEdit1.CopytoClipboard.
>
> Any reason in particular you do them one at a time instead of doing one
> paste with the whole block?
>
> > I then use a kebd_event with CTRL+V (tried SendMessage and PostMessage
> with
> > a WM_PASTE but that doesn't seem to do anything).
>
> I believe you'd have to have the handle to the actual target window to get
> the WM_PASTE to work  There are examples around for doing it with notepad,
> but you're probably better off with the Ctrl+V anyway.
>
> > The basics of the code are :
> >
> > For each line of text :
> > Get text to send
> > Clear RichEdit
> > Paste text into RichEdit
> > Select text in RichEdit
> > RichEdit.CopyToClipboard
> > Call procedure to send the keyboard event
>
> You'd probably have to put in a delay here, perhaps a Sleep with a few mS
of
> delay.  The problem is that you have no way of knowing if the target
> application has accomplished the paste, so you'll have to give plenty of
> delay to be sure that its right.  The clipboard wasn't intended for this
> kind of use, you'd be better of pasting the entire block in one go.
>
> > // end of loop
> > 2) Is there a way to determine how many items are in the clipboard and
> > select which one to paste, as you can see in Word?
>
> Theres only ever one thing on the clipboard.  Anything that provides a
> clipboard history has hooked into the clipboard chain and is just keeping
a
> copy of anything placed on the clipboard.
>
> DK
>
>



From: David Knaack  
Subject: Re: Clipboard (sorry, a bit long, but I wanted to get all th
NewsGroup: borland.public.delphi.language.objectpascal
Date Posted: 10-Feb-2003 at 8:43:28 PST
"Grendel"  wrote in message
news:3e476e1f$1@newsgroups.borland.com...
> I have multiple lines of text that I want to send, so do them one at a
time.
> I paste what I want into a RichEdit box and then use
> RichEdit1.CopytoClipboard.

Any reason in particular you do them one at a time instead of doing one
paste with the whole block?

> I then use a kebd_event with CTRL+V (tried SendMessage and PostMessage
with
> a WM_PASTE but that doesn't seem to do anything).

I believe you'd have to have the handle to the actual target window to get
the WM_PASTE to work  There are examples around for doing it with notepad,
but you're probably better off with the Ctrl+V anyway.

> The basics of the code are :
>
> For each line of text :
> Get text to send
> Clear RichEdit
> Paste text into RichEdit
> Select text in RichEdit
> RichEdit.CopyToClipboard
> Call procedure to send the keyboard event

You'd probably have to put in a delay here, perhaps a Sleep with a few mS of
delay.  The problem is that you have no way of knowing if the target
application has accomplished the paste, so you'll have to give plenty of
delay to be sure that its right.  The clipboard wasn't intended for this
kind of use, you'd be better of pasting the entire block in one go.

> // end of loop
> 2) Is there a way to determine how many items are in the clipboard and
> select which one to paste, as you can see in Word?

Theres only ever one thing on the clipboard.  Anything that provides a
clipboard history has hooked into the clipboard chain and is just keeping a
copy of anything placed on the clipboard.

DK