11
votes

Comment puis-je mettre du texte formaté dans le presse-papiers?

J'écris un test de l'unité pour un utilitaire "Text Scrubber" qui supprimera toute mise en forme, etc. du texte dans le presse-papiers.

Par exemple, si vous copiez un texte d'un document Word ou d'une page Web avec des tonnes de formatage, vous voudrez peut-être la coller dans un autre mot DOC comme un texte ancien normal et simple.

Pour écrire un test de l'unité pour cela, j'ai besoin, bien sûr, pour écrire du code qui met en réalité un texte formaté dans le presse-papiers.

Donc, ma question est - comment puis-je le faire dans le code DELPHI?


5 commentaires

Est-ce que Googling "Delphi Copie dans le presse-papier" aide? Je vois quelques articles écrits de faire cela. Y a-t-il quelque chose de spécifique qui rend ces articles inutiles?


Ouais, ils ne vous disent pas comment mettre quelque chose en qui est formaté ou ce que ce format devrait être. Par exemple, cela n'a pas vraiment aidé: MSDN. microsoft.com/en-us/library/ms649016%28vs.85%29.aspx


Vous savez que le mot et la plupart des applications mettent également un texte formaté sur le presse-papiers dans le texte formaté et aussi simple. Lorsque vous avez collé, vous pouvez choisir le format que vous souhaitez en utilisant la commande "Coller Special". Vous pouvez avoir d'autres raisons d'écrire ce programme, mais si vous passez vraiment d'un mot Doc à un autre mot Doc, tout est construit pour éliminer le formatage.


Mark - Ouais je sais ça. Ce dont j'ai besoin est une façon programmatique de le faire afin que je puisse le tester dans un test unitaire.


Quelle serait géniale si l'IDE Delphi mettrait du code dans 2 formats dans le presse-papiers, de sorte que le code copié et collé dans des courriels ou des documents de mots ait une mise en évidence appropriée au lieu de texte brut ?!


3 Réponses :


9
votes

Voici un exemple sur la manière de copier dans le presse-papier au format HTML: http://www.swissdelphicenter.ch/torry/showcode.php?id=1391

J'ai modifié le code légèrement de sorte qu'il fonctionne dans Delphi 2009. P>

//  If you've ever tried sticking html into the clipboard using the usual CF_TEXT
//  format then you might have been disappointed to discover that wysiwyg html
//  editors paste your offering as if it were just text,
//  rather than recognising it as html. For that you need the CF_HTML format.
//  CF_HTML is entirely text format and uses the transformation format UTF-8.
//  It includes a description, a context, and within the context, the fragment.
//
//  As you may know one can place multiple items of data onto the clipboard for
//  a single clipboard entry, which means that the same data can be pasted in a
//  variety of different formats in order to cope with target
//  applications of varying sophistocation.
//
//  The following example shows how to stick CF_TEXT (and CF_HTML)
//  into the clipboard.

function FormatHTMLClipboardHeader(HTMLText: string): string;
const
  CrLf = #13#10;
begin
  Result := 'Version:0.9' + CrLf;
  Result := Result + 'StartHTML:-1' + CrLf;
  Result := Result + 'EndHTML:-1' + CrLf;
  Result := Result + 'StartFragment:000081' + CrLf;
  Result := Result + 'EndFragment:°°°°°°' + CrLf;
  Result := Result + HTMLText + CrLf;
  Result := StringReplace(Result, '°°°°°°', Format('%.6d', [Length(Result)]), []);
end;

//The second parameter is optional and is put into the clipboard as CF_HTML.
//Function can be used standalone or in conjunction with the VCL clipboard so long as
//you use the USEVCLCLIPBOARD conditional define
//($define USEVCLCLIPBOARD}
//(and clipboard.open, clipboard.close).
//Code from http://www.lorriman.com
procedure CopyHTMLToClipBoard(const str: AnsiString; const htmlStr: AnsiString = '');
var
  gMem: HGLOBAL;
  lp: PChar;
  Strings: array[0..1] of AnsiString;
  Formats: array[0..1] of UINT;
  i: Integer;
begin
  gMem := 0;
  {$IFNDEF USEVCLCLIPBOARD}
  Win32Check(OpenClipBoard(0));
  {$ENDIF}
  try
    //most descriptive first as per api docs
    Strings[0] := FormatHTMLClipboardHeader(htmlStr);
    Strings[1] := str;
    Formats[0] := RegisterClipboardFormat('HTML Format');
    Formats[1] := CF_TEXT;
    {$IFNDEF USEVCLCLIPBOARD}
    Win32Check(EmptyClipBoard);
    {$ENDIF}
    for i := 0 to High(Strings) do
    begin
      if Strings[i] = '' then Continue;
      //an extra "1" for the null terminator
      gMem := GlobalAlloc(GMEM_DDESHARE + GMEM_MOVEABLE, Length(Strings[i]) + 1);
      {Succeeded, now read the stream contents into the memory the pointer points at}
      try
        Win32Check(gmem <> 0);
        lp := GlobalLock(gMem);
        Win32Check(lp <> nil);
        CopyMemory(lp, PChar(Strings[i]), Length(Strings[i]) + 1);
      finally
        GlobalUnlock(gMem);
      end;
      Win32Check(gmem <> 0);
      SetClipboardData(Formats[i], gMEm);
      Win32Check(gmem <> 0);
      gmem := 0;
    end;
  finally
    {$IFNDEF USEVCLCLIPBOARD}
    Win32Check(CloseClipBoard);
    {$ENDIF}
  end;
end;

// Example:

procedure TForm1.Button1Click(Sender: TObject);
begin
  CopyHTMLToClipBoard('Hello world', 'Hello <b>world</b>');
end;


3 commentaires

Génial - exactement ce dont j'avais besoin. Merci.


CopyMemory (LP, PCHAR (Cordes [I]) - PANSICHAR


Strings [0]: = Formathtmllipboardheader (HTMLSTR); -> Strings [0]: = utf8encode (formathtmllipboardheader (htmlstr)); uniquement utf-8 msdn.microsoft.com/en-us/library/aa767917.aspx



10
votes

dans DSIWIN32 Nous avons:

  _STARTUPINFOW = record
    cb: DWORD;
    lpReserved: PWideChar;
    lpDesktop: PWideChar;
    lpTitle: PWideChar;
    dwX: DWORD;
    dwY: DWORD;
    dwXSize: DWORD;
    dwYSize: DWORD;
    dwXCountChars: DWORD;
    dwYCountChars: DWORD;
    dwFillAttribute: DWORD;
    dwFlags: DWORD;
    wShowWindow: Word;
    cbReserved2: Word;
    lpReserved2: PByte;
    hStdInput: THandle;
    hStdOutput: THandle;
    hStdError: THandle;
  end;
  TStartupInfoW = _STARTUPINFOW;
  PStartupInfoW = ^TStartupInfoW;


4 commentaires

Ce code fonctionne mieux que la variante acceptée (j'ai eu des problèmes avec coller dans TrichView composant avec la dernière)


+1 Merci d'avoir partagé ce code - je cherchais juste une copie HTML dans la fonction de presse-papier.


J'ai copié l'unité Dsiwin32 de votre site, mais cela ne compile pas (il se plaint d'un type Tstartupinfow), je suis en cours d'exécution Delhpi 7. Puis-je modifier cela en Tstartupinfo?


+1. Q: In DSIGETHTMLFormatFromClipboard , ne doit pas PCLIPDATA défini comme PANSICHAR pour les versions UNICODE de Delphi (car il est UTF8)?



1
votes

La réponse acceptée de Wouters a été un bon départ, mais ne gère pas les caractères Unicode. J'ai modifié le code exemple pour fonctionner avec Unicode (données HTML et Text). Fuite de mémoire fixe également.

function FormatHTMLClipboardHeader(HTMLText: UTF8String): UTF8String;
const
  CrLf = #13#10;
begin
  Result := 'Version:0.9' + CrLf;
  Result := Result + 'StartHTML:-1' + CrLf;
  Result := Result + 'EndHTML:-1' + CrLf;
  Result := Result + 'StartFragment:000081' + CrLf;
  Result := Result + 'EndFragment:°°°°°°' + CrLf;
  Result := Result + HTMLText + CrLf;
  Result := UTF8String( StringReplace( string(Result), '°°°°°°', Format('%.6d', [Length(Result)]), []) );
end;


//The second parameter is optional and is put into the clipboard as CF_HTML.
procedure CopyHTMLToClipBoard(const str: String; const htmlStr: String = '');
var
  gMem    : HGLOBAL;
  lp      : Pointer;
  HString : UTF8String;
begin
  {$WARN SYMBOL_PLATFORM OFF}
  Win32Check(OpenClipBoard(0));

  try
    Win32Check(EmptyClipBoard);

    if ( htmlStr <> '' ) then
    begin
      // convert to utf8 and add header, which windows html clipboard format requires
      HString := FormatHTMLClipboardHeader( UTF8String( htmlStr ) );

      //an extra "1" for the null terminator
      gMem := GlobalAlloc(GMEM_DDESHARE + GMEM_MOVEABLE, Length(HString) + 1);
      {Succeeded, now read the stream contents into the memory the pointer points at}
      try
        Win32Check(gmem <> 0);
        lp := GlobalLock(gMem);
        Win32Check(lp <> nil);
        CopyMemory(lp, Pointer( HString ), Length( HString ) + 1);
        Win32Check(gmem <> 0);
        SetClipboardData( RegisterClipboardFormat( 'HTML Format' ), gMem);
        Win32Check(gmem <> 0);
      finally
        GlobalUnlock(gMem);
        GlobalFree(gMem);
      end;
    end;

    // Now just place plain unicode text, double buffer size as it's utf16
    gMem := GlobalAlloc(GMEM_DDESHARE + GMEM_MOVEABLE, ( Length(str) + 1 ) * 2);
    {Succeeded, now read the stream contents into the memory the pointer points at}
    try
      Win32Check(gmem <> 0);
      lp := GlobalLock(gMem);
      Win32Check(lp <> nil);
      CopyMemory(lp, Pointer( str ), ( Length( str ) + 1 ) * 2);
      Win32Check(gmem <> 0);
      SetClipboardData( CF_UNICODETEXT, gMem);
      Win32Check(gmem <> 0);
    finally
      GlobalUnlock(gMem);
      GlobalFree(gMem);
    end;

  finally
    Win32Check(CloseClipBoard);
  end;
  {$WARN SYMBOL_PLATFORM ON}
end;


1 commentaires

Une note à toute personne qui tente de tenter - si vous utilisez ce code, vous constaterez que vous constaterez que les appels pour récupérer les données du presse-papier peuvent échouer à cause de l'appel à GlobalFree, si vous avez des problèmes, essayez sans cela.