I would like to retrieve the file size of a file copied into the clipboard.
I read the documentation of TClipboard but I did not find a solution.
I see that TClipboard.GetAsHandle could be of some help but I was not able to complete the task.
Just from inspecting the clipboard I could see at least 2 useful formats:
FileName (Ansi) and FileNameW (Unicode) which hold the file name copied to the clipboard.
So basically you could register one of then (or both) with RegisterClipboardFormat and then retrieve the information you need. e.g.
uses Clipbrd;
var
CF_FILE: UINT;
procedure TForm1.FormCreate(Sender: TObject);
begin
CF_FILE := RegisterClipboardFormat('FileName');
end;
function ClipboardGetAsFile: string;
var
Data: THandle;
begin
Clipboard.Open;
Data := GetClipboardData(CF_FILE);
try
if Data <> 0 then
Result := PChar(GlobalLock(Data)) else
Result := '';
finally
if Data <> 0 then GlobalUnlock(Data);
Clipboard.Close;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if Clipboard.HasFormat(CF_FILE) then
ShowMessage(ClipboardGetAsFile);
end;
Once you have the file name, just get it's size or other properties you want.
Note: The above was tested in Delphi 7. for Unicode versions of Delphi use the FileNameW format.
An alternative and more practical way (also useful for multiple files copied) is to register and handle the CF_HDROP format.
Here is an example in Delphi: How to paste files from Windows Explorer into your application
Related
I never used Indy and am struggling to learn the basic. Took me some time to figure out how to populate the listbox. Now that I have done that how can I download the selected file in the listbox ?
I tried :
procedure TFTP.Button2Click(Sender: TObject);
var
i:integer;
begin
for i := 0 to ListBox1.Items.Count - 1 do begin
if ListBox1.Selected[i] then begin
IdFTP1.Get(listbox1.Selected[i]);
end;
end;
end;
But I am getting :
[dcc32 Error] FTP_Form.pas(75): E2250 There is no overloaded version
of 'Get' that can be called with these arguments
Or do I need to use a savedialog too? Please help me with this. :)
ListBox1.Selected[i] is a Boolean. Note that in the previous line you wrote:
if ListBox1.Selected[i] then begin
Now, look at the TIdFTP.Get() method. It has two overloads:
procedure Get(const ASourceFile: string; ADest: TStream;
AResume: Boolean = false); overload;
procedure Get(const ASourceFile, ADestFile: string; const ACanOverwrite: boolean = false;
AResume: Boolean = false); overload;
You need to provide:
the source filename of the remote file you want to download.
a destination filename or stream to receive the content of the remote file.
I don't know where you intend to obtain these. Presumably the filename comes from the ListBox, which would therefore be ListBox1.Items[i].
What do you want to do with the content you download? Keep it in memory? Save it to a file? Something else? What destination you supply depends on your answers to those questions.
My advice to you is to put the ListBox to one side for the moment, and write a simpler program, one without any UI, that simply downloads a single file from the FTP server. Use a local filename or a TFileStream to save the downloaded content to your local disk. Check that the contents are what you expect. Once you can download one file, you can download any number of files, to other kinds of destinations.
Once you have mastered that, move on to the user interface. Spend some time learning how the ListBox control works, how you populate it, how you read back strings from it, how you test for selection, and so on.
Only when you have a good understanding of all parts involved, then you should you try to fit them together.
One way ....
procedure TFTP.Button2Click(Sender: TObject);
Var
Name{, Line}: String;
begin
Name := IdFTP1.DirectoryListing.Items[ListBox1.ItemIndex].FileName;
SaveDialog1.FileName := Name;
if SaveDialog1.Execute then begin
IdFTP1.Get(Name, SaveDialog1.FileName, true);
end;
end;
Assuming the ListBox contains the remote filenames to download (such as from the TIdFTP.DirectoryListing property after a call to TIdFTP.List()):
procedure TFTP.Button2Click(Sender: TObject);
var
i:integer;
begin
for i := 0 to ListBox1.Items.Count - 1 do
begin
if ListBox1.Selected[i] then begin
IdFTP1.Get(ListBox1.Items[i], 'C:\Some Local Path\' + ListBox1.Items[i]);
end;
end;
end;
I read an UTF8-File, made with Winword, into a Tmemo, using the code below (tried all 2 methods). The file contains IPA pronunciation characters. For these characters, I see only squares. I tried different versions of tmemo.font.charset, but it did not help.
What can I do?
Peter
// OD is an TOpenDialog
procedure TForm1.Load1Click(Sender: TObject);
{
var fileH: textFile;
newLine: RawByteString;
begin
if od.execute (self.Handle) then begin
assignFile(fileH,od.filename);
reset(fileH);
while not eof(fileH) do begin
readln(fileH,newLine);
Memo1.lines.Add(UTF8toString(newLine));
end;
closeFile(fileH);
end;
end;
}
var
FileStream: tFileStream;
Preamble: TBytes;
memStream: TMemoryStream;
begin
if od.Execute then
begin
FileStream := TFileStream.Create(od.FileName,fmOpenRead or fmShareDenyWrite);
MemStream := TMemoryStream.Create;
Preamble := TEncoding.UTF8.GetPreamble;
memStream.Write(Preamble[0],length(Preamble));
memStream.CopyFrom(FileStream,FileStream.Size);
memStream.Seek(0,soFromBeginning);
memo1.Lines.LoadFromStream(memStream);
showmessage(SysErrorMessage(GetLastError));
FileStream.Free;
memStream.Free;
end;
end;
First, you are doing too much work. Your code can be simplified to this:
procedure TForm1.Load1Click(Sender: TObject);
begin
if od.Execute then
memo1.Lines.LoadFromFile(od.FileName, TEncoding.UTF8);
end;
Second, as David said, you need to use a font that supports the Unicode characters/glyphs that are stored in the file. It is not enough to set the Font.Charset, you have to set the Font.Name to a compatible font. Look at the fonts that loursonwinny mentioned.
For these characters, I see only squares.
The squares indicate that the font does not contain glyphs for those characters. You'll need to switch to a font that does. Assuming that your file has been properly encoded and that you are reading in the code points that you intend to.
You can pass TEncoding.UTF8 to the LoadFromFile method to avoid having to add a BOM to the content. Finally, don't call GetLastError unless the Win32 documentation says it has meaning. Where you call it, there is no reason to believe that the value has any meaning.
I'm looking for a Delphi function which returns the file URL path from the Windows path. Is there something for it built-in in Delphi ?
Example:
Input
C:\Users\Documents\File.txt
Output
file:///C:/Users/Documents/File.txt
Thanks
You can use the UrlCreateFromPath API function.Here is the example:
uses
ComObj, WinInet, ShLwApi;
function FilePathToURL(const FilePath: string): string;
var
BufferLen: DWORD;
begin
BufferLen := INTERNET_MAX_URL_LENGTH;
SetLength(Result, BufferLen);
OleCheck(UrlCreateFromPath(PChar(FilePath), PChar(Result), #BufferLen, 0));
SetLength(Result, BufferLen);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(FilePathToURL('C:\Users\Documents\File.txt'));
end;
Look at UrlCreateFromPath(). Note that there are caveats with the file: scheme, though. It is not stanardized across platforms. There are multiple formats to represent the same path in different ways, even just under Windows. Since IE4, the Win32 API standardizes on a single format, but other formats still exist.
I encounter problem on FastReports, it will not print correctly on pages which contain Korean character. It hapens only on Printer HP K5300 jet, T test it using rave and having no problem. I think it a bug for fast reports. I already convert all my reports from rave to FastReports and dont have plan to moved back.
I am planning to get the generated pages as images without saving it to hard drive and then generate a new preports. this time, the generated images will be used and print. I know this solution is not good. this is worable for now While waiting for their responds.
anybody has any idea how to get the images form generated pages?
If you just want to avoid saving a lot of files, you can create a new export class to print the file just after it is created and delete it instantly.
You can create a whole new export class which print the bitmap from memory (for example, using the TPrinter class and drawing the bitmap directly in the printer canvas)... you will learn how checking the source file of the TfrxBMPExport class.
Take this untested code as an example which will guide you how to create a new class to save/print/delete:
type
TBMPPrintExport = class(TfrxBMPExport)
private
FCurrentPage: Integer;
FFileSuffix: string;
protected
function Start: Boolean; override;
procedure StartPage(Page: TfrxReportPage; Index: Integer); override;
procedure Save; override;
end;
{ TBMPPrintExport }
procedure TBMPPrintExport.Save;
var
SavedFileName: string;
begin
inherited;
if SeparateFiles then
FFileSuffix := '.' + IntToStr(FCurrentPage)
else
FFileSuffix := '';
SavedFileName := ChangeFileExt(FileName, FFileSuffix + '.bmp');
//call your actual printing routine here. Be sure your the control returns here when the bitmap file is not needed anymore.
PrintBitmapFile(SavedFileName);
try
DeleteFile(SavedFileName);
except
//handle exceptions here if you want to continue if the file is not deleted
//or let the exception fly to stop the printing process.
//you may want to add the file to a queue for later deletion
end;
end;
function TBMPPrintExport.Start: Boolean;
begin
inherited;
FCurrentPage := 0;
end;
procedure TBMPPrintExport.StartPage(Page: TfrxReportPage; Index: Integer);
begin
inherited;
Inc(FCurrentPage);
end;
In production code you will want to override another methods to initialize and finalize the printer job, cleaning up, etc.
Code is based on FastReport v4.0 implementation of TfrxCustomImageExport, specially for page numbering and file naming. It may require adjustments for other FastReport versions.
You can use the TfrxBMPExport (frxExportImage unit) component to save the report as BMP.
For example, this code will export the report:
procedure ExportToBMP(AReport: TfrxReport; AFileName: String = '');
var
BMPExport: TfrxBMPExport;
begin
BMPExport := TfrxBMPExport.Create(nil);
try
BMPExport.ShowProgress := True;
if AFileName <> '' then
begin
BMPExport.ShowDialog := False;
BMPExport.FileName := AFileName;
BMPExport.SeparateFiles := True;
end;
AReport.PrepareReport(True);
AReport.Export(BMPExport);
finally
BMPExport.Free;
end;
end;
The Export component, in this case, uses a different file name for each page. If you pass 'c:\path\report.bmp' as the filename, the export component will generate c:\path\report.1.bmp, c:\path\report.2.bmp and such.
As usual, you can drop and manually configure the component on any form/data module if you prefer that way.
In this question is mentioned the wcrypt2.
What I need is simply calculate the MD5 of a file. It would be perfect if I could calculate it without having to save it because it is a downloaded file in stream format.
I would like to have the most straightforward way to do that.
Thanks!
Here is a working code for Indy 10:
function MD5File(const FileName: string): string;
var
IdMD5: TIdHashMessageDigest5;
FS: TFileStream;
begin
IdMD5 := TIdHashMessageDigest5.Create;
FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Result := IdMD5.HashStreamAsHex(FS)
finally
FS.Free;
IdMD5.Free;
end;
end;
Regards,
OscaR1
Based on #dummzeuch answere I wrote this function:
function getMD5checksum(s: TStream): string;
var
md5: TIdHashMessageDigest5;
hash : T4x4LongWordRecord;
begin
md5 := TIdHashMessageDigest5.Create;
s.Seek(0,0);
hash := md5.HashValue(s);
result := IntToHex(Integer(hash[0]), 4) +
IntToHex(Integer(hash[1]), 4) +
IntToHex(Integer(hash[2]), 4) +
IntToHex(Integer(hash[3]), 4);
end;
Indy comes with functions for calculating several hashes, MD5 is one of them. Indy is included in all versions of Delphi since at least Delphi 2006 and available as a free download for older versions.
What about:
function GetFileMD5(const Stream: TStream): String; overload;
var MD5: TIdHashMessageDigest5;
begin
MD5 := TIdHashMessageDigest5.Create;
try
Result := MD5.HashStreamAsHex(Stream);
finally
MD5.Free;
end;
end;
function GetFileMD5(const Filename: String): String; overload;
var FileStream: TFileStream;
begin
FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Result := GetFileMD5(FileStream);
finally
FileStream.Free;
end;
end;
As you mentioned, the post you linked to talks about wcrypt2, which is a library of cryptographic routines, including MD5. The post you linked to also seems to indicate that it is available for Delphi 7 since the asker includes output labeled "Delphi 7." You have tagged this question delphi7, so I assume that's the version you're using, too. So what's stopping you from using wcrypt2?
The question links to a copy of wcrypt2.pas, and the copyright dates in that file appear to indicate that the unit was available by the time Delphi 7 was released. Check your installation; you might already have it. If not, then the unit also says that it was obtained via Project Jedi, so you could try looking there for the unit as well.
The answers to your referenced question include example Delphi code and the names of units that come with Delphi for doing MD5. They come with Delphi 2009, so you should check whether they're also available for your version.
Take a look at this implementation of MD5SUM in Delphi. It requires a string for input, but I imagine you can easily make it work with a stream.
MessageDigest_5 would work for this as well.
I use the following function in Delphi 7 with Indy 10.1.5
uses IdHashMessageDigest, idHash, Classes;
...
function cc_MD5File(const p_fileName : string) : string;
//returns MD5 has for a file
var
v_idmd5 : TIdHashMessageDigest5;
v_fs : TFileStream;
v_hash : T4x4LongWordRecord;
begin
v_idmd5 := TIdHashMessageDigest5.Create;
v_fs := TFileStream.Create(p_fileName, fmOpenRead OR fmShareDenyWrite) ;
try
v_hash := v_idmd5.HashValue(v_fs);
result := v_idmd5.AsHex(v_hash);
finally
v_fs.Free;
v_idmd5.Free;
end;
end;
If you use Overbyte http://www.overbyte.eu/frame_index.html just add unit and call function FileMD5 with name of file
uses OverbyteIcsMd5;
....
function GetMd5File:String;
begin
Result := FileMD5(FileName);
end;