How do I produce a .SRM file containing string resources? - delphi

The example I am looking at is in the TurboPower FlashFiler database.
It has, for example, a file ffclcnst.rc which contains
FF_CLIENT_STRINGS RCDATA FFCLCNST.SRM
and I can run
BRCC32 ffclcnst.rc
at the command prompt which seems to compile the .SRM file into a .RES file, but I cannot see how to change the information in the .SRM file. It appears to come from the ffclcnst.str file so I assume there is some way to convert the .STR file into the .SRM file.

The readme tells you:
Most of FlashFiler's error messages are stored in string resource
files having the extension STR. If you change these files, you must
recompile them using the TurboPower String Resource Manager located at
http://sourceforge.net/projects/tpsrmgr
Please note that these are not standard Windows string resources. They're something TurboPower made up. For a full explanation, be sure to read the String Resource Manager's documentation. You can make an ordinary string-table resource in your .rc file, or you can skip the .rc file altogether and declare resourcestring constants directly in your Delphi code. Unless you're editing TurboPower code, or you need to support ancient Delphi versions, I recommend you just use normal string tables.

Related

Official document on the format of the .rc file used in Delphi?

I am trying to find the official document on the .rc resource file format in Delphi, but cannot find any.
What I can see is below:
http://docwiki.embarcadero.com/RADStudio/Sydney/en/Resource_file_(Delphi) (indicate how to include a .rc file)
http://docwiki.embarcadero.com/RADStudio/Sydney/en/Step_3_-_Add_Style-Resources_as_RCDATA_(Delphi) (indicate how to include style as RCDATA resource)
But no official document on the complete format of the .rc file, including the comment format, different built-in resource types, etc.
Update
Original I think the .rc file used in Delphi should be same as those used in Windows such as Visual C++.
However, to add a bitmap resource, in VC, it is:
IDB_BITMAP1 BITMAP "E:\Temp\bar_bugs.bmp"
in Delphi, it can be as well:
IDB_BITMAP1 BITMAP "E:\Temp\bar_bugs.bmp"
But IDB_BITMAP1 in Delphi can be used as a resource name and use directly(such as TBitmap.LoadFromResourceName, but in VC, one must define a constant for IDB_BITMAP1 to work, instead of loading via name directly. So it seems they are a bit different?

How ResourceString Identifiers are generated by delphi compiler?

My question is like Delphi compiler generates and assign numerical Identifiers to all the ResourceStrings when application is compiled, There are few documents which says when ever application is recompiled the numerical Identifiers for Resourcestrings are regenerated, and they warn relying on it because it may change after regenerations. There ate so many third party localization tools that use and store this resourcestring numerical identifiers for internal reference and translation. Is there any way to stop compiler regenerating this resourcestring numerical identifiers or force it to use manually generated numerical identifiers?
You can get a resource-compiler, compilable file from the compiler by specifying the --drc or "Project|Options|Delphi Compiler|Linker|Output resource string .drc file" switch. This will instruct the compiler to generate a .drc file that will contain the resource string contents and the compiler-assigned values.
If you do this for each build, even if the compiler rearranges the assigned values, you will always know what they are. The compiler generates an identifier for each resource string based on the unit-name and the resource string identifier, so that is always stable even if the value changes.
This .drc file can then be translated or otherwise processed and then recompiled into a .res file. This .res file can then be linked into a a special "resource-only" dll with a specific extension other than ".dll" that indicates the language. When the system language is properly set, this dll will then be loaded and the strings will be used instead of the built-in resource.
You don't have any control over how the compiler generates the string table resource, and the numeric identifier.
If you wish to use external tools that rely on the numeric identifier then you should probably build the string table in the classic way. Define the string table in a text file. Compile to a resource and link into a language specific resource DLL. This will make the coding less convenient, and it's for you to decide whether or not that trade off is worth being able to use your external tools.

Delphi : how to check if a file exists (path over 255 characters)

I need to make my delphi app able to check if a file copied using Robocopy is there or not when its path exceeds 255 characters.
I have tried the usual "If FileExists(MyFile) then ... " but it always returns "false" even if the file is there.
I also tried to get the file's date but I get 1899/12/30 which can be considered as an empty date.
A File search does not return anything either.
Prefix the file name with \\?\ to enable extended-length path parsing. For example you would write
if FileExists('\\?\'+FileName) then
....
Note that this will only work if you are calling the Unicode versions of the Win32 API functions. So if you use a Unicode Delphi then this will do the job. Otherwise you'll have to roll your own version of FileExists that calls Unicode versions of the API functions.
These issues are discussed in great length over on MSDN: Naming Files, Paths, and Namespaces.

How to compress multiple folders into one archive?

I have some compression components (like KAZip, JVCL, zLib) and exactly know how to use them to compress files, but i want to compress multiple folders into one single archive and keep folders structure after extract, how can i do it?
in all those components i just can give a list of files to compress, i can not give struct of folders to extract, there is no way (or i couldn't find) to tell every file must be extracted where:
i have a file named myText.txt in folder FOLDER_A and have a file with same name myText.txt in folder FOLDER_B:
|
|__________ FOLDER_A
| |________ myText.txt
|
|__________ FOLDER_B
| |________ myText.txt
|
i can give a list of files to compress: myList(myText.txt, myText.txt) but i cant give the structure for uncompress files, what is best way to found which file belongs to which folder?
The zip format just does not have folders. Well, it kinda does, but they are kind of empty placeholders, only inserted if you need metadata storage like user access rights. But other than those rather rare advanced things - there is no need for folders at all. What is really done - and what you can observe opening zip file in the notepad and scrolling to the end - is that each file has its path in it, starting with "archive root". In your exanple the zip file should have two entries (two files):
FOLDER_A/myText.txt
FOLDER_B/myText.txt
Note, that the separators used are true slashes, common to UNIX world, not back-slashes used in DOS/Windows world. Some libraries would fix back-slashes it for you, some would not - just do your tests.
Now, let's assume that that tree is contained in D:\TEMP\Project - just for example.
D:\TEMP\Project\FOLDER_A\myText.txt
D:\TEMP\Project\FOLDER_B\myText.txt
There are two more questions (other than path separators): are there more folders within D:\TEMP\Project\ that should be ignored, rather than zipped (like maybe D:\TEMP\Project\FOLDER_C\*.* ? and does your zip-library have direct API to pack the folders wit hall its internal subfolder and files or should you do it file by file ?
Those three questions you should ask yourself and check while choosing the library. The code drafts would be somewhat different.
Now let's start drafting for the libraries themselves:
The default variant is just using Delphi itself.
Enumerate the files in the folder: http://docwiki.embarcadero.com/CodeExamples/XE3/en/DirectoriesAndFilesEnumeraion_(Delphi)
If that enumeration results in absolute paths then strip the common D:\TEMP\Project from the beginning: something like If AnsiStartsText('D:\TEMP\Project\', filename) then Delete(filename, 1, Length('D:\TEMP\Project\'));. You should get paths relative to chosen containing place. Especially if you do not compress the whole path and live some FOLDER_C out of archive.
Maybe you should also call StringReplace to change '\' into '/' on filenames
then you can zip them using http://docwiki.embarcadero.com/Libraries/XE2/en/System.Zip.TZipFile.Add - take care to specify correct relative ArchiveFileName like aforementioned FOLDER_A/myText.txt
You can use ZipMaster library. It is very VCL-bound and may cause troubles using threads or DLLs. But for simple applications it just works. http://www.delphizip.org/
Last version page have links to "setup" package which had both sources, help and demos. Among demos there is an full-featured archive browser, capable of storing folders. So, you just can read the code directly from it. http://www.delphizip.org/191/v191.html
You talked about JVCL, that means you already have Jedi CodeLib installed. And JCL comes with a proper class and function, that judging by name can directly do what you want it too: function TJclSevenzipCompressArchive.AddDirectory(const PackedName: WideString; const DirName: string = ''; RecurseIntoDir: Boolean = False; AddFilesInDir: Boolean = False): Integer;
Actually all those libraries are rather similar on basic level, when i made XLSX export i just made a uniform zipping API, that is used with no difference what an actual zipping engine is installed. But it works with in-memory TStream rather than on-disk files, so would not help you directly. But i just learned than apart of few quirks (like instant vs postponed zipping) on ground level all those libs works the same.

Is it possible to change a resource string in Delphi when it is loaded from a resource DLL?

I have a Delphi app with localized resource DLLs.
I would like to do a search and replace on a resource string once it is loaded from the DLL.
Is there any internal procedure to hook into to do this?
I need a way to just do search and replace for any resource string loaded, and not just change a specific resource string.
Raoul.
Yes you have to hook the LoadResString() procedure defined in System.pas.
See for instance how we do in http://synopse.info/fossil/finfo?name=SQLite3/SQLite3i18n.pas
There is everything in this unit code:
For extracting all resource strings (but you may also compile the executable with the "detailed map" option to get the same list);
For replacing all resource strings on the fly, to your expected language;
For caching all resource string, since default LoadResString API can be slow.
You have also similar code around, but this is one included in our Open Source mORMot framework, working from Delphi 6 up to XE2. There is also code to change on the fly all .dfm content (i.e. your forms), from the same translated text file. There is a chapter about that in the framework documentation at http://mormot.net
I think you will get here every code pattern needed for your task.

Resources