I have an AVI file that I pulled from shell32 using Resources Extract. I would like to use this with TAnimate but I can't figure out how to load this file.
I succesfully loaded the AVI into a .RES file using DelphiDabbler's rcdatacreator program (you have to download the "worked example" to get rcdatacreator. However, my issue now is figuring out how to extract the AVI file from the .RES and supplying it to TAnimate.
I am using Delphi 2010:
Any help is appreciated.
As Andreas mentioned (in his now deleted answer), you don't need to use an external tool to add the resource in recent versions of Delphi.
Use Project/Resources and Images... from the IDE menu. Add a new resource by browsing to the folder your .AVI file is in, give it a name, and type in AVI for the Resource Type. (It's not in the list, but you can add it.)
At runtime, use the following code:
// I used CoolAVI as the resource name in my image above,
// so that's the name I need to use here.
Animate1.ResName := 'COOLAVI';
Animate1.Active := True;
Related
I am able to open a CHM file by passing a ShortInteger and casting it as a Word for the dwData parameter. I.E.
Unit Help; //this is where the Id's are set with their description
Interface
Const
Address_File = 35; //delphi identifies Address_File as a shortint
etc..
Call get help pass my ID
GetHelp(Address_File); //call get help pass my ID to open to the Address_File topic
GetHelp procedure
procedure GetHelp(HelpID : Word);
begin
Application.HelpFile := ProgramPath + 'help.chm';
HtmlHelpW(0, PWideChar(Application.HelpFile),HH_HELP_CONTEXT , HelpID);
end;
HtmlHelpW function
function HtmlHelpW(hwndCaller : HWND; pszFile: PWideChar; uCommand : Integer;
dwData : DWORD) : HWND; stdcall; external 'hhctrl.ocx' name 'HtmlHelpW';
As I pass different ShortIntegers I am able to initialize the help file at different sections.
However I can't figure out how the values are mapped. There are some sections in the chm file that I want to be able to map to but the short Integer or context ID associated with them is not documented in the program or is not mapped.
Free Pascal comes with a chmls.exe util that has a command that tries to recover the alias (context) data:
chmls, a CHM utility. (c) 2010 Free Pascal core.
Usage: chmls [switches] [command] [command specific parameters]
Switches :
-h, --help : this screen
-p, --no-page : do not page list output
-n,--name-only : only show "name" column in list output
Where command is one of the following or if omitted, equal to LIST.
list <filename> [section number]
Shows contents of the archive's directory
extract <chm filename> <filename to extract> [saveasname]
Extracts file "filename to get" from archive "filename",
and, if specified, saves it to [saveasname]
extractall <chm filename> [directory]
Extracts all files from archive "filename" to directory
"directory"
unblockchm <filespec1> [filespec2] ..
Mass unblocks (XPsp2+) the relevant CHMs. Multiple files
and wildcards allowed
extractalias <chmfilename> [basefilename] [symbolprefix]
Extracts context info from file "chmfilename"
to a "basefilename".h and "basefilename".ali,
using symbols "symbolprefix"contextnr
extracttoc <chmfilename> [filename]
Extracts the toc (mainly to check binary TOC)
extractindex <chmfilename> [filename]
Extracts the index (mainly to check binary index)
This might be a start, since at least you'll know which pages are exported using an ID, and maybe the URL names will give some information.
The util is in recent releases (make sure you get 2.6.0) and also available in Free Pascal source, which should be convertable to Delphi with relatively minor effort.
Basically the chmls tool was created out of various test codebases. The testprograms decompiled and printed contents of different CHM sections and were used while creating the helpfile compiler, chmcmd, which is also part of FPC.
In Delphi, calling a help file is rather easy. In any VCL Forms application, you can set the HelpContext property of almost any control to a unique Context ID, which corresponds to a particular topic in the Help File. The Help File was compiled with these mappings, but when you decompile it, these mappings are no longer there. You must have access to the original help file project in order to know these ID's.
Set HelpContext of controls to the corresponding Context ID in the Help File
Set HelpType of controls to htContext to use the HelpContext ID
Assign Application.HelpFile to the appropriate location of the CHM file
When pressing F1 anywhere in your application, the help file will open based on the Help Context ID on the control, or its parent control
If you don't have the original project, and you don't want to re-create it, then you would have a long task of iterating through the Context ID's of your help file. Try to call the help file starting from 0 through 1,000 or possibly 50,000, depending on the size of it.
A practice I implement is a set of constants in a designated unit called HelpConstants.pas which is shared across our common application base. Each constant name uniquely and briefly describes the topic which it represents. Upon starting the application, I dynamically assign these Context ID's to their corresponding controls (usually forms) and VCL takes care of the rest.
I got the utility Marco suggested from
https://github.com/alrieckert/freepascal_arm/blob/master/packages/chm/bin/i386-win32/chmls.exe
(download by selecting View Raw).
I was able to extract all the context tags from the .chm help file and add the one I was interested in to my C++ Builder program by calling Application->HelpJump().
HTH
I have an .il file which I can compile without any problems. I can strong name it and so without any issues. But I am not able to set the file version via the attribute as I would expect it. How can I set the FileVersion for an assembly when using ilasm?
If I do a round trip I get always a .res file which does contain only binary data which is not readable. What is inside this res file and can I edit it?
The code does not work
.assembly myAssembly
{
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = { string('1.2.3.4') }
The issue can be solved by using the .res file. It is not sufficient to do a round trip with ildasm and ilasm. The IL file does not reference the .res file. I had to add it to the ilasm call manually. The data in the res file seemed to contain the infos which are written into the PE header which is ok for me.
The final command line needed was
ilasm test.il /dll /res:test.res
I still do not know what exactly is inside the res file but I can exhange it with the meta data information of any other assemlby that I create manually and then decompile it to replace the metadata of the original assembly as I need.
It seems not many people are doing such stuff.
How can I make a single executable package that contains DLL and Image Resource Files?
Then how do I extract them from my Executable at Runtime?
Option 1 using the IDE (Delphi 2007 or Higher):
You can click the Project menu, then select Resources..., which you can load any file into. For your purpose this would be RC_DATA.
Option 2 without the IDE
If you do not have the above option, you will need to use the BRCC32 (Borland Resource Compiler) to create a .RES file from RC file, which you then link to your Application. To link Resource files without using the IDE, try the following:
Lets say for example we want to add a a couple of DLL files, and the name of the DLL files are MyLib1.dll and MyLib2.dll, to add this open Notepad, and type the following:
MYLIB1 RCDATA "..\MyLib1.dll"
MYLIB2 RCDATA "..\MyLib2.dll"
Make sure the ..\xxx.dll paths are correct, so obviously you need to edit that.
Now you need to save this as a .rc file, so File>Save As..(make sure the dropdown filter is All Files .) and name it MyResources.rc. Now you need to use the Resource Compiler to generate the Res file, using this console command:
BRCC32 MyResources.RC
You can write that command by using the Command Prompt, Start Menu > Run > cmd.exe, alternatively you can find the BRCC32.exe inside the bin folder of your Delphi setup and drag the MyResource.RC file onto.
This will create a Res file named MyResources.RES which you can include inside the Main Delphi form of your Application, like so:
{$R *.dfm}
{$R MyResources.res}
you can extract the resources by using something like this:
procedure ExtractResource(ResName: String; Filename: String);
var
ResStream: TResourceStream;
begin
ResStream:= TResourceStream.Create(HInstance, ResName, RT_RCDATA);
try
ResStream.Position:= 0;
ResStream.SaveToFile(Filename);
finally
ResStream.Free;
end;
end;
What I've found out to be convenient, is to use a .zip container.
Then you'll have two implementations:
Append some .zip content to an existing .exe, and the .exe code will retrieve the .zip content on request;
Embed the .zip content as a resource, then extract on request each content.
Solution 1 will add the .zip content after compilation. Whereas 2 will add the .zip content at compilation. For a setup program, I think solution 1 makes sense to me. For a way of retrieving some needed files (libraries, and even bitmaps or text) which are linked to a particular exe release, solution 2 could be envisaged.
Using .zip as format make it easy to parse the content, and allow compression. Using a tool like TotalCommander, you can even read the .zip file content with Ctrl+PgDown over the .exe. Very convenient.
You'll find in this link how you implement solution 1, and in this link (same page, but another post) how to use the TZipRead.Create() constructor to directly access to a .zip bundled as resource. You'll find in our repository how it works with working applications: e.g. how we embedded icons, textual content and graphviz + spell-checker libraries in the SynProject executable.
About performance, there is no difference between the two solutions, at least with our code. Both use memory mapped files to access the content, so it will be more or less identical: very fast.
I'm looking for a ready-to-use piece of code that would be able to read and modify Delphi .res files. The thing is that I need to create an application that will be compiling many Delphi projects at once (using the dcc32.exe file). However, it is necessary for me to change file version and language before compilation, and as far as I know, I have to modify the .res file to do that.
Have you come across any code that would give me an interface to .res files allowing me to modify the data contained in it? The thing is that I want to change only those two pieces of information keeping the rest unchanged. This is why I can't compile my own .res file based on a script.
An application executed from a command line would also be OK if it allows to be called with parameters and does what I need it to do.
Thank you very in advance!
If all you need is to add file version resource then create appver.rc file, compile it with brcc32 and in one of your app unit (for example appver.pas) add {$R appver.res} (as Marian noticed you must turn off Delphi project option to include version info).
I created command line programs that increase build numbers in .rc file, create new branch/tag in SVN with new version in branch name, compiles .rc to .res, and build application.
My .rc files with such info (Polish language) looks like:
#define IDR_VERSION1 1
IDR_VERSION1 VERSIONINFO LOADONCALL MOVEABLE DISCARDABLE IMPURE
FILEVERSION 7,28,7,17
PRODUCTVERSION 7,28,7,17
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
FILEOS VOS_DOS_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0
{
BLOCK "StringFileInfo"
{
BLOCK "041504E2"
{
VALUE "CompanyName", "xxx\0"
VALUE "FileDescription", "yyy\0"
VALUE "ProductName", "zzz\0"
VALUE "FileVersion", "7.28.7.17\0"
VALUE "ProductVersion", "7.28.7.17\0"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0415, 1250
}
}
For all things .res, look at Colin Wilson's "XN Resource Editor", for which he provides the source code: http://www.wilsonc.demon.co.uk/d10resourceeditor.htm
And probably all you need is his resource utility library:
http://www.wilsonc.demon.co.uk/d9resourceutils.htm
I haven't used this source, but if I needed it, that's the first place I'd look. His resource editor is very useful, btw.
There is ChangeRes which seems to match your needs.
Check out sources:
http://code.google.com/p/gedemin/source/browse/trunk#trunk/Gedemin/Utility/IncVerRC
It is our utility which reads .RC file with version information and increments build number. We use it inside our build process. Here is an excerpt:
incverrc.exe ..\gedemin\gedemin.rc
"%delphi_path%\brcc32.exe" -fogedemin.res -i..\images gedemin.rc
"%delphi_path%\dcc32.exe" -b gedemin.dpr
The utility uses TIncVerRc class written by Chris Morris.
Check Resource Tuner Console on www.heaventools.com. They position that product for tasks like yours. Also there's a free rcstamp tool on CodeProject.
(Using Delphi 5)
I am attempting to open a log file using the following code:
// The result of this is:
// C:\Program Files\MyProgram\whatever\..\Blah\logs\mylog.log
fileName := ExtractFilePath(Application.ExeName) + '..\Blah\logs\mylog.log';
// The file exists check passes
if (FileExists(fileName)) then
begin
logs := TStringList.Create();
// An exception is thrown here: 'unable to open file'
logs.LoadFromFile(fileName);
end;
If I relocate the log file to C:\mylog.log the code works perfectly. I'm thinking that the spaces in the file path are messing things up. Does anyone know if this is normal behavior for Delphi 5? If it is, is there a function to escape the space or transform the path into a windows 8.3 path?
I'm pretty sure that Delphi 5 handles spaces in filenames ok but it has been a very long time since I have used that specific version. Is the file currently open by another process? It also could be a permissions issue. Can you instead of loading it into a tStringList, try opening it with a tFileStream with the filemode set to "fmOpenRead or fmShareDenyNone".
fStm := tFileStream.Create( filename, fmOpenRead or fmShareDenyNone );
then load your tStringlist from the stream:
Logs.LoadFromStream ( fStm );
Are you sure its not the "..\" thats causing the problem rather than the spaces. Have you tried to see if it works at
c:\My\Path\nospaces\
If so and you are always using the ..\ path, maybe write a simple function to remove the last folder from your application path and create a full correct pathname.
It's odd that Delphi 5 would throw errors about this. I know of an issue with FileExists failing on files with an invalid last-modified-date (since it internally uses FileAge), but it's the opposite here. Instead of using "..\" I would consider risking the current path, and loading from a relative path: LoadFromFile('..\Something\Something.log'); especially for smaller applications, or by calling ExtractFilePath twice: ExtractFilePath(ExtractFilePath(Application.ExeName))
I'm pretty sure Delphi has always handled spaces so I doubt that is the issue.
You don't show the full path. Any chance it is really long? For example I could believe an issue with paths longer than 255 characters.
It's also a bad idea to put log files under Program Files. Often normal users are not given permission to write to anything under Program Files.
Delphi 5 can open files with spaces - that is certainly not the problem. To prove it, try copying it to c:\my log.log- it should open fine.
Is there any more information in the error message you receive? The most likely thing is that someone else (perhaps your own program) is still writing to the log.
The spaces are not a problem. While the '..' could be a problem in Delphi 5, mosts probably the file is locked by the process that writes to it. If you have control of it, make sure it opens the file with fmShareDenyWrite and not fmShareExclusive or fmShareCompat (which is the default).
Also, you can use:
fileName := ExpandFileName(ExtractFilePath(Application.ExeName) + '..\Blah\logs\mylog.log');
to obtain the absolute path from a relative path.
Also, as others have said, it is not good idea to write anything in Program Files. Regular users (that are not Administrators or Power Users) do not have rights to write there (although in Vista is will be virtualized, is is still not a good idea). Use the appropriate Application Data folder for the user (or all users). This folder can be obtained using:
SHGetFolderPath(0,folder,0,SHGFP_TYPE_CURRENT,#path[0])
where folder is either CSIDL_COMMON_APPDATA or CSIDL_LOCAL_APPDATA. See this delphi.about.com article for an example.
Simple :
// if log file = "C:\Program files\mylog.log"
// you'll get :
// »»»»» fileName = 'C:\Program files..\Blah\logs\mylog.log'
// if log file = "C:\mylog.log"
// you'll get :
// »»»»» fileName = 'C:..\Blah\logs\mylog.log'
Try this code instead, I'm pretty sure it will fit your needs :
fileName := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName))
+ '..\Blah\logs\mylog.log';
Regards,
Olivier
Delphi 5 has never had a problem opening files with spaces and I am still using it since it is uber stable and works great for older XP apps. You need to check your code closely.