-
Content Count
1301 -
Joined
-
Last visited
-
Days Won
28
Posts posted by Sherlock
-
-
My last excursion to Google Gemini was successful at the end, but kinda bumpy still. I started out by asking
QuoteI want to protect a configuration file for my Delphi application on Windows against changes and unauthorized access. I was thinking about using encryption, but how should the password be protected?
Which gave me three possibilities ask the user for the key, use hardware keys or DPAPI. It also explained (quite lengthy) what the pros and cons of each solution are. I was kinda looking for DPAPI anyway so I went for that with
QuoteAre there any ready-made components or units that use or facilitate DPAPI?
That resulted in naming the API calls CryptProtectData and CryptUnptotectData stating they should be declared in
Winapi.CryptDPAPI.pas
or more general inWinapi.Windows.pas.
The main advantage being the lack of a password entirely, everything being managed by Windows itself. It then presented me with some example codeunit MyDPAPIUnit; interface uses Winapi.Windows, Winapi.CryptDPAPI, System.SysUtils; function ProtectData(const AData: TBytes; const ADescription: string = ''; AForLocalMachine: Boolean = False): TBytes; function UnprotectData(const AData: TBytes; var ADescription: string; AForLocalMachine: Boolean = False): TBytes; implementation function ProtectData(const AData: TBytes; const ADescription: string = ''; AForLocalMachine: Boolean = False): TBytes;
and so forth. Of course a first compile with me integrating this into a test project failed, because there is no Winapi.CryptDPAPI.
QuoteIn Delphi 12.2 the unit Winapi.CryptDPAPI does not seem to exist.
I am a nice person, am I not?
Well of course Gemini then said I was totally right, and that indeed everything required could be found in WinAPI.Windows. Then rambled on about why it got so confused, and basically blaming Embarcadero for not consistently placing specific API segments in their own units like has happened with WinAPI.Messages or WinAPI.ShellAPI. It then presented me with a corrected unit ready to be integrated into my project...or so it thought.
In its implementation of ProtectData and UnprotectData it used a constant for a specific flag, and that did not go over well with the compiler:
QuoteNow Delphi says CRYPTPROTECT_LOCAL_MACHINE is an unknown identifier. What is happening here?
Here is what it said then 😄
QuoteMy mistake! You're absolutely right, CRYPTPROTECT_LOCAL_MACHINE isn't an identifier directly declared as a constant in Delphi that would simply be found in the Winapi.Windows unit. I apologize for this inaccuracy.
The flags for the CryptProtectData and CryptUnprotectData functions are defined in the Windows API as decimal or hexadecimal values. You can use these values directly in Delphi.
It then fixed the unit by defining the needed constant correctly. But alas, more errors incoming. I'm still trying to be nice and perhaps lead the machine to realize its own mistakes 🙂
QuoteWhat is CryptProtectData?
Yeah, it did not react to that slight hint but gave me a crash course on DPAPI. Only after I wrote
QuoteDelphi reports that this is an undeclared identifier.
basically rubbing its nose in the mess, it finally noticed and responded accordingly
QuoteYou're absolutely right! I sincerely apologize for the ongoing confusion. I'm embarrassed that this bug persisted. It seems I was mistaken about the details of DPAPI constants in Delphi.
OK, I thought, that looks good. But it took a bad turn quickly yet again, because it continued with the following
QuoteCRYPTPROTECT_LOCAL_MACHINE is actually not a fixed part of the Delphi declarations in Winapi.Windows.
The correct way to set this flag is to use the decimal value 4 or the hexadecimal value $00000004 directly.
and provided me with a "revised" version of the unit where the only correction was more comments, and the constant was now called CRYPTPROTECT_LOCAL_MACINE_FLAG. Oh, goody. Now it really should work, but I didn't bother with a test compile, I was still feeling merciful and wrote
QuoteIt's about the CryptProtectData method, which is apparently unknown.
I'm guessing by now it is trying to get rid of this issue as fast as possible, because the explanations and excuses are getting shorter and lamer
QuoteOkay, I understand the problem. I'm sorry this confusion continues. If CryptProtectData is reported as an unknown identifier, it means that the function itself isn't correctly declared in the Delphi units you're using, or that a necessary import statement is missing.
Well, d'uh!
So finally it comes up with the perfect reason:
QuoteThe cause: API import in Delphi
Delphi declares many Windows API functions in its Winapi.* units. For cryptography functions, including DPAPI, the key unit is Winapi.CryptAPI.
It looks like my previous assumption that Winapi.Windows covers all cryptography functionality was incorrect. While Winapi.Windows contains basic Windows types and many general API functions, specialized areas like cryptography are often encapsulated in separate units.
And follows up with the perfect solution for the home run:
QuoteThe solution: Add Winapi.CryptAPI ✅
To use CryptProtectData and CryptUnprotectData and their associated structures (such as DATA_BLOB), you must add Winapi.CryptAPI to your uses clause.
Note the proud addition of the checkmark, so this must be official... it even updated the entire unit. Now it must be right.... but wait, how did this get started again?
QuoteThere is no Winapi.Cryptapi
I'm getting pretty good at shattering this machines dreams.
QuoteYou're absolutely right! My previous information was inaccurate on this point, and I sincerely apologize for the ongoing confusion.
The CryptProtectData and CryptUnprotectData functions, as well as their associated structures such as DATA_BLOB, are not directly declared in Delphi in a unit called Winapi.CryptAPI. Instead, they are part of the basic Windows API declarations.
In Delphi, these functions, although they are part of cryptography, are typically made accessible through an external declaration in one of the core units, since they are located in the Windows crypt32.dll.
I believe it's on to something here
QuoteThe correct procedure in Delphi
To use CryptProtectData and CryptUnprotectData in Delphi, you must manually declare them as external functions imported from crypt32.dll.
Here is the corrected and complete example, which should now work without the nonexistent units:
This actually sound correct, so I gave the revised unit a go. And it worked as expected. So that was about an hours worth of work, then had a lunch break and came up with some ideas for improvement. So with renewed strength and the feeling of being on the home stretch I wrote
QuotePlease adapt the methods to encrypt and decrypt an object of type TFileStream
It obliged gladly and even provided me with a sample snippet of how to call this glorious code, which it also explained in depth. Actually this could be a nice side effect of AIs, if one takes the time to really read all that jibber jabber.
Buuuuuuuut, again, the unit would not compile because how the AI thought TFileStreams needed to be handled.
QuoteAStream.SetEndOfFile does not exist
(I'm already out of patience...this short into the second half, oh my)
QuoteYou're right again! My sincere apologies for the persistent errors in the code examples. I'm sorry I gave you incorrect information here.
The SetEndOfFile method doesn't actually exist directly for TFileStream. It's a Windows API function that applies to file handles, and is typically achieved by setting the Size property of the TFileStream.
It then went on and on and finally concluded that this wasn't even necessary because of how TFileStream.WriteBuffer takes care of that automatically. So that was needed to be done was to remove these erroneous calls to inexistent methods...Done, the newly improved unit was presented with a nice remark at the end
QuoteThank you again for your patience and thoughtful feedback. I strive to make the information as accurate as possible.
Yeah, we'll see about that, I have more nuisance to test you with
QuoteIt would be useful if the UnprotectFileStream method could output a TMemoryStream
Prompt answer
QuoteYou have a good idea! It would actually be very convenient if UnprotectFileStream could directly return a TMemoryStream, as this would greatly simplify further processing of the decrypted data in memory without having to go through a temporary file.
You see that too? Now it's just buttering me up! I sense troubles ahead. To my surprise, the new version worked right away. So I got bold
QuoteI would like to change the input for ProtectFileStream to a file name
Just that one method...but
QuoteThis is a very useful change! It's often more convenient to call a function directly with a filename instead of having to create a TFileStream first.
I'll modify the ProtectFileStream and UnprotectFileStreamToMemory functions to accept a filename (string) as input. The functions will then internally create, use, and release the file stream.
Grrr...at this point I was happy with the one change for the Protect method, and ignored the Unprotect. Copying only parts of the code now. It worked. Again I was provided with samples for calling and quite extensive explanations on the whys and hows. A neat learning experience I completed by asking some questions concerning this technique and security aspects (i.e. could one know how this file was encrypted?)) and possible issues when running this in a Citrix environment. I feel the answers given where quite good and sounded altogether correct.
All in all this has been a pretty cool experiment with the free version of Google Gemini 2.5 Flash. I know there is a Pro version, but I'm not yet ready to spend money on that. Please note I did the session in German, so some translation errors might have slipped in either on my side or the AIs. The entire session can be viewed here: https://g.co/gemini/share/a6d5936220bf
-
1
-
-
I'm kind of baffled that some folks suggested to do this with HTML....does that compile into a standalone application nowadays, not requiring a browser to run? I mean, the background is supposed to be a desktop, isn't it?
-
Just to clear and sum up: The error is in the 414 lines of code above this totally fine function. So, until one of the following two things happens, this will turn in to a merry game of guessing:
1) You provide us with the top 414 lines of code
2) You let your IDE format the code and discover formatting is "out of whack" beginning somewhere above line 415, and home in on the problem yourself
In any case, I do hope you will provide us with the solution to this riveting riddle.
-
Rand is OK, but I'm a more modern, WordStar kind of guy. Just love me my WordStar diamond, and loved Delphi for incorporating WordStar shortcuts.
-
2 hours ago, DelphiUdIT said:if some MVP were authorized to release some other substantial news, even if not seasoned with technical details
If you are a current subscriber to Delphi, you should have received an invitation to Beta test....
-
Just as a side remark: macOS is a desktop OS as well. And it has a quite comfortable market share in the US private and commercially, in Europe however mostly in doctors offices. Though the Apple silicon piqued the interest of many a business.
-
On 6/21/2025 at 9:27 AM, Keesver said:You can contact us at kees[dot]vermeulen[at]a-dato[dot]net if you are interested.
@ChrisChuah Should be pretty straight forward...
-
Any helpers installed? Such as GExperts, cnPack or MMX?
-
It works for me as well. Just sayin'...
-
There is an iOS simulator via XCode available on the Mac you'll need to package and sign the app anyway. But if you don't want to buy a Mac (Minis are quite cheap though), you can rent a Mac online via services like MacInCloud, MacStadium or OakHost just to name a few.
-
1
-
-
You might consider adding scanning exemptions. Folders, that should not be scanned, because of high performance penalties. But you should keep an eye on those folders by other means.
-
4 hours ago, Roger Cigol said:...everything is so much easier !
Except carrying the rig around.
*SCNR*
-
2
-
-
To expand (or perhaps reiterate) that answer: Components are not installed (or even bought) just to have them. If during programming you discover you would benefit from a ready to use component for some functionality over writing it yourself then you should consult the internet or perhaps this forum on where to find such a component. Event hen, if it is a commercial component, you might want to calculate the cost benefit over writing it yourself. Furthermore it is most often preferable to have sources for components to ensure their use over time.
-
2 hours ago, Der schöne Günther said:Would you be willing to tell more about your daily usage, maybe in a separate thread? I'd be absolutely interested in typical day to day usage, battery runtimes, standby/wakeup times and where it could start to get tricky (old printer drivers, shell extensions, obscure software,...).
I think it would be fair to say that Windows on ARM is not for legacy environments. It is intended for new mainstream devices. So no immediate support for decades old printers and other old hardware should be expected. However(!) as soon as it gets more traction I expect that to change.
-
1
-
-
You should rather read that as "they will open up the next major construction site as soon as there is money and manpower available, and it will take several releases until it is usable"...and even that should be taken with a grain of salt.
-
1
-
-
-
Perhaps this will cause the DOGE to rethink their plans for COBOL (*) ...as a matter of fact I'm sure of it.
(*) https://www.wired.com/story/doge-rebuild-social-security-administration-cobol-benefits/
-
-
OK, so good news: I finally got it. Thanks to "msix hero" an OS tool specifically made for everything msix. https://github.com/marcinotorowski/MSIX-Hero.
It just signed my little test project right away. Now I can go on working. Thanks everyone for your contributions and support.
-
1
-
-
That site has been up for a week. You can work fast with Delphi, but you can't work magic.
-
How does this construct work on Windows? As expected?
-
On 3/23/2025 at 11:56 AM, Vincent Parrett said:Signotaur can sign MSIX files
Oh, that sounds great. For a test run, I downloaded the installer and am quite overwhelmed by the further needs (service user, SSL-certificate, Server) to run the "server". For a small test if my msix could be signed by this, it seems quite the overkill. 😞
-
2 minutes ago, DelphiUdIT said:I don't know if there is difference, but have you tried to use:
"C:\Program Files (x86)\Windows Kits\10\App Certification Kit\signtool"
I have, and that uses an older version of signtool:
"C:\Program Files (x86)\Windows Kits\10\App Certification Kit\signtool.exe" sign /v /a /fd SHA256 C:\Win\SignTest\Win64\Release\SignTest\bin\SignTest.msix The following certificate was selected: Issued to: My Company Issued by: Certum Extended Validation Code Signing 2021 CA Expires: Sat Jan 08 12:11:18 2028 SHA1 hash: E7C16794EA23F573DE3EA32B5B564717CE84CC75 Done Adding Additional Store SignTool Error: An unexpected internal error has occurred. Error information: "Error: SignerSign() failed." (-2147024885/0x8007000b)
File version is 10.0.19041.685. I'm using 10.0.26100.0 which at least gives a slightly better error message.
-
1
-
-
I actually don't want to upload to the store. I need this to be able to create a Kiosk application for Windows 10/11. At least that is how I understand what I have found on the net so far. msix is not a must, but recommended. Also signed msix is not a must, but from a customers POV nice to have. Thanks @Patrick PREMARTIN for the /tr hint. I just shortened the command for ease of use. I really hope once the easy signature works, adding the time server will not be an issue.
Using "Claude Code" with Delphi
in General Help
Posted
@Die Holländer That would be my ultimate goal. But this time I actually wanted to "grow" a project with the machine.