Copy file to clipboard in Delphi - delphi

Anybody know how to copy file in Delphi? It likes press Ctrl+ C on a file or folder, and then we can Paste at somewhere ? I just know how to copy a text by Clipbrd Unit, but i don't know with a file, folder !
Please help me !

Use the CF_HDROP format to store the file/folder's full path, or use the CF_SHELLIDLIST format to store the file/folder's ITEMIDLIST. Refer to MSDN for more details:
Shell Clipboard Formats
Alternatively, convert the folder/file path(s) to ITEMIDLIST value(s) using SHParseDisplayName(), ILCreateFromPath(), or other similar function, then use SHCreateDataObject() to create an IDataObject from them, and then pass that to OleSetClipboard().

Clipboard and drag&drop have a lot in common. Most of libraries for support of drag&drop also have all what you need for clipboard. For example check this lib:
http://melander.dk/delphi/dragdrop/
It is free, with full sourcecode and has a lot of examples, including for clipboard operations.
One of examples is DragDrop\Demos\Unicode\DragDropUnicode.dproj, it has popup command "Copy to clipboard":
procedure TForm1.ActionFileCopyExecute(Sender: TObject);
begin
if (FFiles = '') then
DropFileSource1.Files.Text := LoadResString(0)
else
DropFileSource1.Files.Text := FFiles;
DropFileSource1.CopyToClipboard;
end;
Hope it helps.

Related

Add ini file as resource file and read from it

I would like to add an ini file to my delphi project as a resource file.
I know where you go to add a file as a resource file:
Project > Resources and Images > Add
But once thats done what else do I need to do to be able to read from the file? I haven't used resource files before.
Is there any documentation on the process?
Thanks,
The built-in INI file classes in the RTL, providing in the System.IniFiles unit, require the INI file to be a disk file. So you could extract the resource to disk and read it from there.
If you don't like the idea of that then you could write your own INI file parser that operated on a stream rather than a file. You could use the code of TMemIniFile to guide you. Copy that code and replace LoadValues with code to read from a stream rather than a file. Or if you look hard enough then you may well find a third party INI parser that operates on streams.
If you are prepared to consider other formats then you might use JSON rather than INI. The built-in JSON parser does not require the input data to reside on disk. They can operate on in-memory strings, which sounds rather more convenient.
This above text is in fact nonsense. Thank you to Remy for pointing that out. You can use TMemIniFile and its SetStrings method to parse INI content that does not reside on disk. It goes like this:
Put your INI content into a resource as a string.
Load that resource into a string variable.
Create a TStringList, and assign the string variable to the Text property of the string list.
Create a TMemIniFile.
Call SetStrings on the TMemIniFile passing the string list.
Or:
Put your INI content into a resource as a string.
Create a TResourceStream object to read that resource.
Create a TStringList object.
Call LoadFromStream on the string list passing the resource stream.
Create a TMemIniFile.
Call SetStrings on the TMemIniFile passing the string list.
Having said all of this, it seems odd that you would choose to do this at all. Wouldn't it be simpler just to hard code the configuration information in a unit, as a series of constants?
Using the "Resources and Images" dialog, add the .ini file to the project as a RCDATA resource type. Then, you can load it at runtime like this:
uses
..., Classes, IniFiles;
var
Ini: TMemIniFile;
List: TStringList;
Strm: TResourceStream;
begin
Ini := TMemIniFile.Create;
try
List := TStringList.Create;
try
Strm := TResourceStream.Create(HInstance, 'ResourceIDHere', RT_RCDATA);
try
List.LoadFromStream(Strm);
finally
Strm.Free;
end;
Ini.SetStrings(List);
finally
List.Free;
end;
// use Ini as needed...
finally
Ini.Free;
end;
end;
To add the files in the executable, be sure to add a .rcfile (not the .ini files directly), for example inis.rc (so in the source file dpr you'll have {$R 'inis.res' 'inis.rc'}) and write in this file a list like this:
this 100 "this.ini"
that 100 "that.ini"
If you've stored the ini files in a (relative) directory, be sure to double the backslashes since this in C-syntax. (The 100here is the resource type, there's no number assigned to ini-files specifically so we'll use an unassigned number. The best next thing is 23 which is assigned to RT_HTML, see below)
If you're not using groups (and lines with just [GroupName]), I'd suggest you use plain TStringList objects and their Values property. To load them with the data, use something like this:
var
sl:TStringList;
r:TResourceStream;
begin
sl:=TStringList.Create;
try
r:=TResourceStream.Create(HInstance,'this',MAKEINTRESOURCE(100));
try
sl.LoadFromStream(r);
finally
r.Free;
end;
//sl.Values['Setting']
finally
sl.Free;
end;
end;
imho, an ini file is just a text file to distribute with an application so you can control behavior of the application in one particular environment. For example, you could store a language in "language.ini", read it from your source code, and present the GUI based on that language.
To accomplish this, your ini file contains:
[general]
language=Russian
then read it from Delphi:
...
uses Inifiles;
...
var CurrentLanguage:string;
...
Ini := TIniFile.Create('C:\somedir\languages.ini');
CurrentLanguage := Ini.ReadString('General', 'language', 'English');//if key isn't found, language is English
Ini.free();
So basically it contains TEXT info... as said above, if you add it as a resource, you might as well hardcode it. Resources should be used primarily for binary data (an image, audio file, video, etc).

Extract zip file to TStream using zlibar in Lazarus

I'm trying to extract a zip file from a TMemoryStream to another TMemoryStream using zlibar in Lazarus. From what I can tell, my code follows the examples found here. I am using a simple zip archive with one text file in it. The zip archive was created using PowerArchiver, nothing special. Here is my code:
uses
zlibar;
var
z, Dest: TMemoryStream;
unZip: TZLibReadArchive;
begin
z := TMemoryStream.Create;
z.LoadFromFile('kov.zip');
unZip := TZLibReadArchive.Create(z);
UnZip.ExtractFileToStream(0, Dest);
I am getting this error: "ZLibError(2) corrupt file or not a correct file type."
See zlibar.pas here: https://dl.dropbox.com/u/8899944/files/zlibar.pas
Any ideas why I am getting this error? Thanks.
The Zlibar library does not read zip files. It reads and writes a custom archive format. You can tell because the table-of-contents format described in zlibar.pas is completely different from the one used in zip files.
The FreePascalArchivePackage link looks like it might someday provide what you want, although the page last had significant changes in 2007.
There's also the ZipFile package, which appears to come with Lazarus.
Just a quick guess: Try to set z.Position := 0 before unZip := TZLibReadArchive.Create(z);.

Problem adding lots of strings to a TStringList

I have a problem adding strings to a TStringList. I've searched other posts but couldn't find an answer to this.
What I'm trying to do is to add a big amount of strings to a TStringList (more than 14000) but somewhere in the process I get an EAccessViolation. Here's the code I'm using:
procedure TForm1.FormCreate(Sender: TObject);
begin
List := TStringList.Create;
List.Duplicates := dupAccept;
end;
procedure TForm1.ButtonStartClick(Sender: TObject);
begin
List.Clear;
List.Add('125-AMPLE');
List.Add('TCUMSON');
List.Add('ATLV 4300');
List.Add('150T-15');
List.Add('TDL-08ZE');
List.Add('RT20L');
List.Add('SIN LINEA');
List.Add('TIARA');
List.Add('FL200ZK1');
List.Add('FL250ZK1');
List.Add('SIN LINEA');
List.Add('CENTAURO-70 S.P.');
List.Add('CORSADO');
{ This list continues to about 14000 strings...}
List.Add('VOSJOD 2');
List.Add('Z 125');
List.Add('ZUMY');
List.Add('NEW AGE 125');
List.Add('SIN LINEA');
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(List);
end;
¿What's wrong with this code? The list contains duplicate strings so I set the Duplicates property to dupAccept. I was able to load the list using LoadFromFile, but I don't want to have a text file outside my application.
I hope you can help me!!! Please tell me if you need any further information.
Thank you very much. I really appreciate your help.
The suggestions for using an external file are on the mark here. However, your post indicates your desire for not having an external file. I would then suggest you link the file to the executable as a resource. You can easily do this following these steps:
Place all the strings into a text file called stringdata.txt (or whatever name you choose). Then create a .rc file of whatever name you choose and put the following into it (STRING_DATA can be any identifier you choose):
STRING_DATA RCDATA "stringdata.txt"
Create a .res file from the .rc:
BRCC32 <name of rc>.rc
Now reference this file from the source code. Place the following someplace in the unit:
{$R <name of res>.res}
Instead of loading from a file stream, load from a resource stream:
StringData := TResourceStream.Create(HInstance, 'STRING_DATA', RT_RCDATA);
try
List.LoadFromStream(StringData);
finally
StringData.Free;
end;
If you do command-line automated builds, I would suggest you keep the .rc file under source control and build the .res during the build process. This way you can also keep the stringdata.txt file under source control and any edits are automatically caught on the next build without having to explicitly build the .res file each time the .txt file changes.
What Delphi version are you using? Some older versions had a bug in the memory manager that can cause an access violation when trying to reallocate an array to a size that's too large.
Try adding FastMM4 to your project to replace the old memory manager and see if that helps.
Also, you're probably better off keeping the list in an external file. Yes, it's another file, but it also means that you can change the list without having to recompile the entire program. This also makes creating (and distributing!) updates easier.
Mason is probably right for the cause of the AV; this is quite a large array to grow.
On a side note, when doing such a long processing on a StringList, it's recommended to surround it by BeginUpdate/EndUpdate to avoid firing any update event.
Even if you don't have any now, they might be added later and you'll get problems.
Set list.capacity to the number of items you plan to add, immediately after you create the list. Alternatively, place the list in an RC file (named other than with the name of your project) and add it to your project. This gets compiled into your application, but does not involve executable code to create the list.
I would also worry about compiler integrity with a 14,000 line procedure. People have found other cases where going beyond anything reasonable breaks the compiler in various ways.
You may also want to try THashedStringList, could see a speed boost (although not in this function), although I'm not sure if the add method is a whole lot different.
try using the following instead of your code to add the strings to the StringList
var
Str: string;
begin
Str := '125-AMPLE' + #13#10;
Str := Str + 'TCUMSON' + #13#10;
Str := Str + 'ATLV 4300' + #13#10;
Str := Str + '150T-15' + #13#10;
................
List.Text := Str;
end;

embedded file into delphi exe application (not as a separate file from the appliaction)

i want to embedded a file (any kind of type) to my exe application and be able to extract in the remote to use it, i know how do it by embedded into resource,but i don't want to place the files in the app directory, i want to store all files (like .rec) into my exe, in c# it is possible to store as text file and then read it by FileStream but in Delphi the resource files is separate from the exe file.
is there any solution to do this ? Thanks a lot!
You should make an .rc file and add that to your project. The content of the RC file is like:
FIXED48 IMAGE ..\Resources\Fixed48x48.png
MENU16 IMAGE ..\Resources\Menu16x16.png
TICK SOUND ..\Resources\Tick.wav
PING SOUND ..\Resources\Ping.wav
Now after you do a build you can load one of these fikles using a TResourceStream:
procedure TdmReportGeneral.InsertLogo(Memo: TStringList; View: TfrView);
var
S: TResourceStream;
begin
if (View is TfrPictureView) and (View.Name = 'Logo') then begin
S := TResourceStream.Create( 0, 'FIXED48', 'IMAGE' );
try
// do something useful... TfrPictureView(View).Picture.MetaFile.LoadFromStream( S );
finally
S.Free();
end;
end;
end;
You should be able to get the Delphi compiler to link your resource into your EXE by adding it as a {$R myresource.res} pragma in a unit in your project. You can then get a handle to it via a call to FindResource when you need to read it.
This article takes you through the appropriate steps.
DelphiDabbler has a great article on this very topic. They even include 2 example projects for download that show how to embed a file as a resource, and how to read it back.
You can download a worked example that
demonstrates what we've described here
– it uses the above code. The zip file
contains a pair of projects. The first
is a program that embeds a supplied
rich text file in a resource file. The
second program includes the resource
file and displays the rich text in a
rich edit component as above.

Open an ANSI file and Save a a Unicode file using Delphi

For some reason, lately the *.UDL files on many of my client systems are no longer compatible as they were once saved as ANSI files, which is no longer compatible with the expected UNICODE file format. The end result is an error dialog which states "the file is not a valid compound file".
What is the easiest way to programatically open these files and save as a unicode file? I know I can do this by opening each one in notepad and then saving as the same file but with the "unicode" selected in the encoding section of the save as dialog, but I need to do this in the program to cut down on support calls.
This problem is very easy to duplicate, just create a *.txt file in a directory, rename it to *.UDL, then edit it using the microsoft editor. Then open it in notepad and save as the file as an ANSI encoded file. Try to open the udl from the udl editor and it will tell you its corrupt. then save it (using notepad) as a Unicode encoded file and it will open again properly.
Ok, using delphi 2009, I was able to come up with the following code which appears to work, but is it the proper way of doing this conversion?
var
sl : TStrings;
FileName : string;
begin
FileName := fServerDir+'configuration\hdconfig4.udl';
sl := TStringList.Create;
try
sl.LoadFromFile(FileName, TEncoding.Default);
sl.SaveToFile(FileName, TEncoding.Unicode);
finally
sl.Free;
end;
end;
This is very simple to do with my TGpTextFile unit. I'll put together a short sample and post it here.
It should also be very simple with the new Delphi 2009 - are you maybe using it?
EDIT: This his how you can do it using my stuff in pre-2009 Delphis.
var
strAnsi : TGpTextFile;
strUnicode: TGpTextFile;
begin
strAnsi := TGpTextFile.Create('c:\0\test.udl');
try
strAnsi.Reset; // you can also specify non-default 8-bit codepage here
strUnicode := TGpTextFile.Create('c:\0\test-out.udl');
try
strUnicode.Rewrite([cfUnicode]);
while not strAnsi.Eof do
strUnicode.Writeln(strAnsi.Readln);
finally FreeAndNil(strUnicode); end;
finally FreeAndNil(strAnsi); end;
end;
License: The code fragment above belongs to public domain. Use it anyway you like.

Resources