Although I had used some of the procedures in the component I sent
you, basically the area I was having problems with is this:

           DataBuffer := GlobalLock(Data);
           try
             DataSize := GlobalSize(Data);
             OutFile.Write(DataSize, SizeOf(DataSize));
             OutFile.Write(DataBuffer^, DataSize);
           finally
             GlobalUnlock(Data);
           end;
        
        I'm going to have to spend a couple of days and really study up on
pointers.  I've never had a reason to use them until now!  I know that's
hard to believe, but true!  Also, exactly what is the purpose of the
GlobalLock?  I was referring to specially registered formats, but I found in
the SDK some functions that should be able to give me that information.
Just for simplicity's sake I would probably like to store the formats in a
separate field.  I've used Widestrings ONLY as required by a few API calls
without truly understanding why.  What type could I use to store them...as
TStrings?  Is there anyway to make use of them without converting them from
their integer values first?  I couldn't find any but that doesn't mean it
isn't possible!  Thanx much for the code examples.  It's much easier for me
to understand yours!    

>From "Robert Meek" 
Personal e-mail:  [EMAIL PROTECTED]
dba / "Tangentals Design"
Visit us at:  www.TangentalsDesign.com
Home of "The Keep"!

Member of:  "Association of Shareware Professionals"
Moderator for:  "The Delphi", "Delphi-DB", and "Delphi-Talk" programming
lists at elists.org,
and proud to be a donator to the Jedi VCL 3.0. 


-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf
Of Rob Kennedy
Sent: Tuesday, April 12, 2005 3:48 PM
To: Borland's Delphi Discussion List
Subject: Re: Oh boy...need pointer help...addendum!

Robert Meek wrote:
> Yes I asked the wrong question!  What I meant to ask was as I
> obviously have to place things back on the clipboard that are in a
specially
> registered format, how do I do that not knowing what the format is?

But you *do* know the format. You had to know the format in order to get 
the data off the clipboard in the first place. When you store the data 
to a file, also store the name of the format.

> I
> haven't found anyway to use the numeric constants for these special
> types...it seems you need to know the CF_ constant type?  And there is no
> listing I can find to use for converting from one to the other!  Also, how
> can I save what is on the clipboard to a stream so it can be loaded into a
> blob along with it's format type so I can then load it back into the
> clipboard later?  There's nothing in the Clipbrd unit that I can use for
> that.

If I wanted to save the contents of the clipboard in all available 
formats to a single file, this is the code I would use:

function GetFormatName(const Format: UInt): WideString;
var
   Len: Integer;
begin
   if Format < $c000 then begin
     Result := SysUtils.Format('#%u', [Format]);
   end else begin
     Len := 400;
     SetLength(Result, Len);
     Len := GetClipboardFormatNameW(Format, PWideChar(Result), Len);
     Win32Check(Len <> 0);
     SetLength(Result, Len);
   end;
end;

procedure SaveClipboardToFile(const FileName: WideString);
var
   OutHandle: THandle;
   OutFile: TStream;
   Format: DWord;
   FormatName: WideString;
   NameLen: LongWord;
   Data: THandle;
   DataBuffer: Pointer;
   DataSize: LongWord;
begin
   Win32Check(OpenClipboard(0));
   try
     OutHandle := CreateFileW(PWideChar(FileName), Generic_Write, 0, 
nil, Create_Always, File_Attribute_Archive or File_Flag_Sequential_Scan, 0);
     Win32Check(OutHandle <> Invalid_Handle_Value);
     try
       OutFile := THandleStream.Create(Integer(OutHandle));
       try
         Format := EnumClipboardFormats(0);
         while Format <> 0 do try
           FormatName := GetFormatName(Format);
           NameLen := Length(FormatName);
           if NameLen = 0 then continue;
           OutFile.Write(NameLen, SizeOf(NameLen));
           if NameLen > 0 then OutFile.Write(FormatName[1], NameLen * 
SizeOf(FormatName[1]));

           Data := GetClipboardData(Format);
           Win32Check(Data <> 0);

           DataBuffer := GlobalLock(Data);
           try
             DataSize := GlobalSize(Data);
             OutFile.Write(DataSize, SizeOf(DataSize));
             OutFile.Write(DataBuffer^, DataSize);
           finally
             GlobalUnlock(Data);
           end;
         finally
           Format := EnumClipboardFormats(Format);
         end;
         Assert(Format = 0);
         if GetLastError <> Error_Success then RaiseLastOSError;
         // Use 0 to designate end of data
         OutFile.Write(Format, SizeOf(Format));
       finally
         OutFile.Free;
       end;
     finally
       CloseHandle(OutHandle);
     end;
   finally
     CloseClipboard;
   end;
end;

It's naive. It doesn't account for private clipboard formats, and it 
also doesn't make any effort to detect and skip synthesized clipboard 
formats.

The procedure saves the clipboard data in a list. First it writes the 
name of the format, and then it writes the data. Both the name and the 
data get prefixed by their lengths first so that they can be read back 
correctly later. Below is a procedure that should be able to read the 
data and put it back on the clipboard.

function GetFormatNumber(const Name: WideString): UInt;
begin
   if Name[1] = '#' then begin
     Result := StrToInt(Copy(Name, 2, MaxInt));
   end else begin
     Result := RegisterClipboardFormatW(PWideChar(Name));
   end;
end;

procedure LoadClipboardFromFile(const FileName: WideString);
var
   InHandle: THandle;
   InFile: TStream;
   Format: DWord;
   FormatName: WideString;
   NameLen: LongWord;
   Data: THandle;
   DataBuffer: Pointer;
   DataSize: LongWord;
begin
   Win32Check(OpenClipboard(0));
   try
     Win32Check(EmptyClipboard);
     InHandle := CreateFileW(PWideChar(FileName), Generic_Read, 0, nil, 
Open_Existing, File_Attribute_Archive or File_Flag_Sequential_Scan, 0);
     Win32Check(InHandle <> Invalid_Handle_Value);
     try
       InFile := THandleStream.Create(Integer(InHandle));
       try
         InFile.ReadBuffer(NameLen, SizeOf(NameLen));
         while NameLen <> 0 do begin
           SetLength(FormatName, NameLen);
           InFile.ReadBuffer(FormatName[1], NameLen * 
SizeOf(FormatName[1]));

           Format := GetFormatNumber(FormatName);

           InFile.ReadBuffer(DataSize, SizeOf(DataSize));
           Data := GlobalAlloc(GMem_Moveable or GMem_DDEShare, DataSize);
           Win32Check(Data <> 0);
           try
             DataBuffer := GlobalLock(Data);
             Win32Check(Assigned(DataBuffer));
             try
               InFile.ReadBuffer(DataBuffer^, DataSize);
               SetClipboardData(Format, Data);
             finally
               GlobalUnlock(Data);
             end;
           except
             GlobalFree(Data);
             raise;
           end;

           InFile.ReadBuffer(NameLen, SizeOf(NameLen));
         end;
       finally
         InFile.Free;
       end;
     finally
       CloseHandle(InHandle);
     end;
   finally
     CloseClipboard;
   end;
end;

I use a special format for clipboard format names because the documentat 
for GetClipboardFormatName suggests that the built-in formats don't have 
names.

-- 
Rob

_______________________________________________
Delphi mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi


_______________________________________________
Delphi mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi

Reply via email to