How to save RegIniFile as IniFile in Delphi? - delphi

My Win32 application uses a registry key utilizing TRegIniFile like this:
MyData:=TRegIniFile.Create('\Software\MyApp');
The registry key has subkeys and values.
How can I export all the data as INI file utilizing TIniFile?

Related

Saving Delphi LockBox 3 generated RSA keys to file - incomprehensible content. How to get readable strings?

As I understand, then public and private key files generated by e.g. https://travistidwell.com/jsencrypt/demo/ is the standard format for RSA keys.
I am trying to generate just the same format keys with Turbo LockBox 3. I am generating keys according to this tutorial http://lockbox.seanbdurkin.id.au/Generate+an+RSA+key and I am saving the generated keys using the code:
procedure TMainForm.GenerateKeysBtnClick(Sender: TObject);
var FStream: TFileStream;
begin
Signatory.GenerateKeys;
FStream:=TFileStream.Create('D:\Cryptic\keys\keys.txt', fmOpenReadWrite);
try
Signatory.StoreKeysToStream(FStream, [PartPublic, PartPrivate]);
finally
FStream.Free;
end;
end;
But the content of the generated file is incomprehensible - I am putting only part of it here due to being afraid that it may contain some sensitive data as I can not clearly see what it contains exactly:
3 # GŹŁīÖŅŠŖ,‡?«ą
˙ßN1?ą›1ź‡&4’C_hsÉųVŻKŖa¸AtāøB īMnSę>Xć|
Is this content somehow encoded or password-protected. It may be. But I did not specified any passwrod. I expect that file will contain private and public keys clearly separated and using the basic characters only (even more - documentation says that the file will contain 2 pairs of keys, separate key pair for the encryption/decryption), but there is no such recognisable content.
How to save LockBox 3 keys in the readable format? E.g. that I can use as a strings for encryption/decryption later?

resolving network shortcut

I added some FTP servers via network shortcuts to windows.
How can I get the FTP address via the WinAPI?
With SHGetFolderPath / CSIDL_NETHOOD, I can get the location of the target.lnk file. But how can I get the FTP URL of that file?
A "normal" .lnk file, I can resolve with this:
ShellLink := CreateComObject(CLSID_ShellLink) as IShellLink;
ShellLink.QueryInterface(IPersistFile, PersistFile);
PersistFile.Load('C:\Test.lnk', STGM_READ);
ShellLink.Resolve(WindowHandle, 0);
Filename[0] := #0;
ShellLink.GetPath(PChar(#Filename[0]), Length(Filename), pfd, 0);
... but this does not work for the Target.lnk files of the network shortcuts to ftp://host/ adresses.
IShellLink::GetPath is used to retrieve a file system path (only drive letter or UNC roots). This is not clear from the documentation but it uses SHGetPathFromIDListEx internally and MSDN has this to say about that function:
Converts an item identifier list to a file system path
If you want the raw shortcut target your best bet is usually IShellLink::GetIDList. You can get the parsing name by using SHGetNameFromIDList(..., SIGDN_DESKTOPABSOLUTEPARSING, ...) on the id-list.

Delphi CommonAppDataFolder seems un-writeable

I get the common app data folder to store my application related files. Eg log files and ini config files. I use the following code:
const
CSIDL_COMMON_APPDATA = $0023;
function TSpecialFolders.GetSpecialFolder(
const ASpecialFolderID: Integer): string;
var
vSFolder : pItemIDList;
vSpecialPath : array[0..MAX_PATH] of Char;
begin
SHGetSpecialFolderLocation(0, ASpecialFolderID, vSFolder);
SHGetPathFromIDList(vSFolder, vSpecialPath);
Result := vSpecialPath;
end;
function TSpecialFolders.GetCommonDocumentsFolder: string;
begin
result := GetSpecialFolder( CSIDL_COMMON_DOCUMENTS );
end;
This works fine on my Windows 7 box and allows my app to write folders and files.
On a customers PC (I think its an older version of windows, because the screen shot has the word "start" on the start button) my app is unable to write files into that path.
On my PC the returned path is:
C:\ProgramData\
with me adding extra folders like so:
mycompany\myapp\logs\
mycompany\myapp\db\
with text files being saved in those folders.
On my customer's PC the function returns:
C:\Documents and Settings\All Users\Application Data
I am unable to write text files into the directory structure there.
Is there a better function I should be using, or a better common file folder?
Edit for SilverWarrior
these are the special folders on my customer's PC.
AppDataFolder : C:\Documents and Settings\Admin\Application Data
CommonAppDataFolder : C:\Documents and Settings\All Users\Application Data
CommonDocumentsFolder : C:\Documents and Settings\All Users\Documents
LocalAppDataFolder : C:\Documents and Settings\Admin\Local Settings\Application Data
MyDocumentsFolder : C:\Documents and Settings\Admin\My Documents
The LocalAppDataFolder has "Admin" in the path suggesting that admin rights would be needed. Is that right?
The CSIDL_COMMON_APPDATA folder is protected by default and only adminstrators have write access to it.
To gain access for all users the administrator has to create a directory inside and grant the needed rights to the users. This task is typically done by an installer for your application (fi InnoSetup has also an option to grant the needed rights to such folders).
The problem is that you are trying to save that data into AppData folder which is intended for all users. By default writing into this folder requires Administrative rights.
So instead of using CSIDL_COMMON_APPDATA (AppData folder for all users) use CSIDL_LOCAL_APPDATA (curent users AppData folder). Writing to curent user AppData folder does not require elevated rights so it shoud work fine.
Well, armed with info from here and a double-hop remote desktop connection to my customer's pc I went in prepared to do battle with the Windows permissions system - only to find that the problem was due to the application's ini file was set to read only.
Clickity click. Problem solved.
All comments about the common app data folder being restricted may still apply as the customer is running his account as administrator on XP SP3.
Thank you for your help.

Any way to guess the mime type on Delphi XE2?

I need to guess the mime type with the purpose of fill the "Content-Type" header for some file uploads.
I fail to found a solution for it.
I wish to call something like: GetMimeType('C:File.jpg') and get back image/jpg.
Best if is multiplataform (for win/osx) but will be enough if only for windows.
Try using the FindMimeFromData Function.
FindMimeFromData contains hard-coded tests for (currently 26) separate
MIME types (see Known MIME Types). This means that if a given buffer
contains data in the format of one of these MIME types, a test exists
in FindMimeFromData that is designed (by scanning through the buffer
contents) to recognize the corresponding MIME type.
from urlmon.pas
function FindMimeFromData(
pBC: IBindCtx; // bind context - can be nil
pwzUrl: LPCWSTR; // url - can be nil
pBuffer: Pointer; // buffer with data to sniff - can be nil (pwzUrl must be valid)
cbSize: DWORD; // size of buffer
pwzMimeProposed: LPCWSTR; // proposed mime if - can be nil
dwMimeFlags: DWORD; // will be defined
out ppwzMimeOut: LPWSTR; // the suggested mime
dwReserved: DWORD // must be 0
): HResult; stdcall;
Also this article to see hot it works MIME Type Detection in Internet Explorer
IE uses GetClassFileOrMime and FindMimeFromData API to detect the mime type of data/files (UrlMon unit in Delphi).
MIME Type Detection in Internet Explorer
The CLSID returned from GetClassFileOrMime could be located in the registry under HKEY_CLASSES_ROOT\CLSID\<clsid>\MimeTypes. (also FileExtensions, FriendlyName).
The registry also holds a MIME database under: HKEY_CLASSES_ROOT\MIME\Database\Content Type.
But since the list of known MIME types is relatively small you could hold that as a resource XML (or whatever) and simply fetch it from there. This will supprt both Windows and OSX.
For file upload operation you can simply always use application/octet-stream.
Indy has TIdMimeTable class (IdGlobal) and it uses a fixed list plus inspecting the registry HKEY_CLASSES_ROOT (see FillMimeTable). If no match is found application/octet-stream is used.
You should probably want to inspect the file content at the server side once the file is uploaded, and not rely on the headers because the ContentType could be tampered at the client side, and also not match with the registry at the server-side.
Internet Direct (Indy) contains a class for this:
class TIdThreadSafeMimeTable
in unit IdCustomHTTPServer
Code example in a HTTP server application:
Response.ContentType :=
Response.HTTPServer.MIMETable.GetFileMIMEType(FileName);
How many file types are you talking about? Maybe you can just create a list of types you want to support.
I can imagine these lists to be available on the internet as well, for instance
here: http://www.webmaster-toolkit.com/mime-types.shtml
here: http://webdesign.about.com/od/multimedia/a/mime-types-by-file-extension.htm
here: List of ALL MimeTypes on the Planet, mapped to File Extensions?
here: http://hul.harvard.edu/ois/systems/wax/wax-public-help/mimetypes.htm
Just get the file extension using ExtractFileExt and check it agains one of those lists. A file doesn't have a mime type in it, so you'll need to use either this list of file extensions, or determine the type by reading the file headers, which is harder and just as unreliable.

Loading the output from TOleContainer.SaveAsDocument

I have an existing database with blobs contain OLE compound files. I have a requirement to read these OLE compound files and open them in the Delphi 7 TOleContainer control.
Note that I don't have the source of the app that reads and write to the database. The database remains in active use, so my solution will be used on an ongoing basis, not just for a one-off data extraction.
TOleContainer has a SaveAsDocument method, and by experimentation I have found that, for a given file, this method produces OLE compound files which are identical to those created in the database when that file is added.
However, TOleContainer does NOT have a corresponding LoadFromDocument method. It has other Load* and Create* methods, but none seem capable or suitable for loading the output from SaveAsDocument.
The delphi 7 implementation of SaveAsDocument is this, from the OleCtnrs.pas module:
procedure TOleContainer.SaveAsDocument(const FileName: string);
var
TempStorage: IStorage;
PersistStorage: IPersistStorage;
begin
CheckObject;
if FModSinceSave then SaveObject;
FOleObject.QueryInterface(IPersistStorage, PersistStorage);
if PersistStorage <> nil then
begin
OleCheck(StgCreateDocFile(PWideChar(WideString(Filename)), STGM_READWRITE
or STGM_SHARE_EXCLUSIVE or STGM_CREATE, 0, TempStorage));
OleCheck(OleSave(PersistStorage, TempStorage, False));
PersistStorage.SaveCompleted(nil);
end;
end;
Please provide an implementation of LoadFromDocument which is capable of loading the output from SaveToDocument, and which I can use to patch OleCtnrs.pas. Or else point me to an existing solution.
Thanks!
You have to load the file by using TOleContainer.CreateObjectFromFile. Do not use TOleContainer.LoadFromStream/File, that only works with files that are saved with TOleContainer.SaveToStream/File. Files saved that way get a Delphi specific header containing a four byte code (BDOC) and size (and maybe something more).
According to the documentation for Delphi 2007 (should be the same for ), you can use 'TOleContainer.LoadFromStream'. From the Delphi 7 help file (emphasis mine):
Call LoadFromStream to load an OLE object from a stream. If OldStreamFormat is true, LoadFromStream loads OLE objects saved by a TOleContainer object as well as OLE objects saved using the current format; if OldStreamFormat is false, LoadFromStream will not load OLE objects saved by the library. If there's already an OLE object in the container, it is destroyed and any changes the user made to it are discarded.

Resources