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

