While I don’t think that nice looking icons should be high on the priority list, it’s Uwe’s decision, not mine. I sent some of the money I got donated to GExperts his way, just because I like the tool.
I blogged about the Embarcadero License Center (ELC) and how to use it remotely. But I never went to the trouble of explaining the different kinds of license types that are available for Delphi (after all: I don’t sell these licenses, so why bother?). But somebody else just did: CodePartners blogged about Network Licensing in RAD Studio. It gives a pretty good overview.
I for one can definitely recommend switching from Named User to Network Named User licenses if you often need to install Delphi on a new computer (I need that rather often) or have a significant turnover of developers over the years.
Network licensing is supported in Delphi 2007 and later.
In theory it is simple to install the dotNet 2.0 framework on Windows 10: Just go to “Programs and Features”, select “Turn Windows Features on or off”, set the checkmark for “.NET Framework 3.5 (includes .NET 2.0 and 3.0)”, press OK and let Windows download the necessary files from Windows Update.
Unfortunately this only works most of the time. If you are unlucky like me and it doesn’t, you will start an odyssey of downloading installers from Microsoft (which also fail, because they try to download files from Windows Update for whatever reason), using the dism tool and possibly Power Shell to install it offline (both of which failed too in my case) and then either despair or find a reference to the “Missed Features Installer”.
When I arrived there, I was very suspicious (and so should you!) of downloading and using such a 3rd party installer. I used the download from Computer Bild not because I think they are the most brilliant computer magazine in Germany (they are not) but at least I trust them not to distribute malware (which is more than I trust the computer magazine CHIP). In addition, I used Virus Total to scan the installer. It gave me a thumbs up, so I was brave enough to run it.
Guess what? It worked. I now have a working .NET 3.5 and 2.0 framework on my computer and could finally install the program I actually wanted to install: The AVT Universal Package for accessing a camera.
Sometimes your program needs to block the screen saver from automatically kicking in. My use case was that the program was recording data and whenever the screen saver was active, the data was lost (No idea why, it probably had something to do with the way HID is implemented in Windows.)
So I was looking for a way to fix that without forcing the user to turn off the screen saver. The methods that used to work under Windows XP no longer work in Windows 7 and later (I don’t care about Vista), so I googled and found this question on StackOverflow. The Windows API functions PowerCreateRequest + PowerSetRequest mentioned in the highest voted answer looked promising. Unfortunately they don’t seem bo be available in Delphi (Delphi 2007, which I used for that project, is too old to know them, but I coudn’t find them in Delphi 10.3 either). The first task was therefore to get a function declaration for Delphi. Google didn’t help here which meant that I had do create them myself. Not a big deal:
type TPowerCreateRequest = function(_Context: PReasonContext): THandle; stdcall; TPowerSetRequest = function(_Handle: THandle; _RequestType: TPowerRequestType): LongBool; stdcall; TPowerClearRequest = function(_Handle: THandle; _RequestType: TPowerRequestType): LongBool; stdcall;
I prefer loading such functions at runtime rather than the program not starting because some external reference is not avaiable. These functions are exported by kernel32.dll.
FDllHandle := SafeLoadLibrary(kernel32); PowerCreateRequest := GetProcAddress(FDllHandle, 'PowerCreateRequest'); PowerSetRequest := GetProcAddress(FDllHandle, 'PowerSetRequest'); PowerClearRequest := GetProcAddress(FDllHandle, 'PowerClearRequest'); if not Assigned(PowerCreateRequest) or not Assigned(PowerSetRequest) or not Assigned(PowerClearRequest) then raise EOsFunc.Create(_('Could not initialize the PowerXxxxRequest functions from kernel32.'));
Usage is not without its own problems. First, I had to declare the constants and parameters:
const POWER_REQUEST_CONTEXT_VERSION = 0; POWER_REQUEST_CONTEXT_DETAILED_STRING = 2; POWER_REQUEST_CONTEXT_SIMPLE_STRING = 1; type PReasonContext = ^TReasonContext; TReasonContext = record Version: ULONG; Flags: DWORD; case Boolean of False: ( SimpleReasonString: PWideChar; ); True: ( Detailed: record LocalizedReasonModule: HMODULE; LocalizedReasonId: ULONG; ReasonStringCount: ULONG; ReasonStrings: PPWideChar; end; ); end; type TPowerRequestType = ( PowerRequestDisplayRequired = 0, PowerRequestSystemRequired = 1, PowerRequestAwayModeRequired = 2, PowerRequestExecutionRequired = 3);
Now, how do these functions work?
The first thing to do is creating a power request with PowerCreateRequest. This function requires a PReasonContext pointer which must be initialized correctly. The Version and Flags fields are simple: Assign one of the POWER_REQUEST_CONTEXT_xxx constants declared above. But what aobut the other fields? I decided to go with the simple case, that is: Set Flags to POWER_REQUEST_CONTEXT_SIMPLE_STRING and provide a value for SimpleReasonString.
var FRequestHandle: THandle; FContext: TReasonContext; FReason: array[0..255] of WideChar; // [...] FContext.Version := POWER_REQUEST_CONTEXT_VERSION; FContext.Flags := POWER_REQUEST_CONTEXT_SIMPLE_STRING; FContext.SimpleReasonString := @FReason; FRequestHandle := PowerCreateRequest(@FContext); if FRequestHandle = INVALID_HANDLE_VALUE then RaiseLastOSError;
Where FReason is an array of WideChar. My tests showed that the TReasonContext record and the reason string it points to must be available through the lifetime of the reason context. If it isn’t, the reason displayed by the powercfg tool (see below) will be corrupted. Therefore I did not use a WideString but a static array.
After the power request has been created, calls to PowerSetRequest and PowerClearRequest are possible.
This call prevents the screen saver from starting automatically. A call to PowerClearRequest supposedly turns that off again (but I haven’t tested it).
I mentionend the powercfg tool above. It’s a Windows command line tool that among other functionality can display processes that have active power requests. e.g.
powercfg /requests DISPLAY: [PROCESS] \Device\HarddiskVolume2\Source\dzlib\tests\BlockScreenSaver\BlockScreenSaver.exe test SYSTEM: None. AWAYMODE: None. EXECUTION: None. PERFBOOST: None.
The string “test” is the reason I passed to PowerCreateRequests.
I mentioned that failing to preserver the reason string results in a corrupted message in the display. It looked like this:
powercfg /requests DISPLAY: [PROCESS] \Device\HarddiskVolume2\Source\dzlib\tests\BlockScreenSaver\BlockScreenSaver.exe ?a?E?I???↑?E?↑?E?↑?E?↑?E?↑
Note that this tool requires administrator privileges (but power requests don’t).