Blocking the Windows Screen Saver in Delphi

 Delphi, Windows, Windows 10, Windows 7, Windows 8.1  Comments Off on Blocking the Windows Screen Saver in Delphi
May 222019
 

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.

  Win32Check(PowerSetRequest(FRequestHandle, PowerRequestDisplayRequired));

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).

I have added this code to my dzlib. It’s in u_dzOsUtils. There is also a simple test / demo program BlockScreenSaver.

If you would like to comment on this, go to this post in the international Delphi Praxis forum.

 Posted by on 2019-05-22 at 14:15

Don’t give the user any information!

 Windows, Windows 10, Windows 7  Comments Off on Don’t give the user any information!
Mar 282019
 

… seems to be the motto of Microsoft.

How else can you explain that a recent update of Windows 7 and Windows 10, that broke older versions of one of our programs (no idea yet what exactly is the problem, but the error code indicates an out of memory error) has different effects.

Windows 7 shows a dialog that the program could not be started and even gives some additional information. But that’s not good enough, the user could be irritated by telling him a program has crashed. So Windows 10 goes a step further and simply does … nothing. The program starts (as you can verify in the task manager), but nothing appears on the screen.

If you have administrator privileges, you can look into the event log (If know how to do that). If you haven’t or don’t know how to, you are lost.

<sarcasm>Great feature, guys!</sarcasm>

 Posted by on 2019-03-28 at 16:04

Filter multiple criteria in Windows Explorer

 Windows, Windows 7, Windows 8.1  Comments Off on Filter multiple criteria in Windows Explorer
Nov 092016
 

Note to self: It is possible to filter on multiple criteria – e.g. extensions – in Windows Explorer by combining them with OR:

.txt OR .doc
  • The OR must be written all upper case (AND is also possible).
  • *.txt will not work
  • It will search recursively
  • A semicolon (as in file filters) does not work.

More on filtering, grouping and searching here.

 Posted by on 2016-11-09 at 12:01

Force “unidentified networks” to be private or public in Windows 7

 Windows, Windows 7  Comments Off on Force “unidentified networks” to be private or public in Windows 7
Oct 282016
 

Windows 7 has got an annoying feature that categorises network connections to be public, home or work networks. This might work for others but it has never worked for me. Even worse, for some reason the link that usually allows the user to change the network type sometimes is not available.

Microsoft even has got Knowledge base entry KB2578723 for that problem, which unfortunately didn’t work for me. I could change the current network, but after a reboot it again categorised the same network as unidentified network and public.

The solution is described in this article on sevenforums.com. Either use the Local Security Policy editor or RegEdit to change the setting how to treat unidentified networks. This setting is usually missing from the registry, so the keys must be created first. The easiest way to do that is the .reg file you can download from the page linked above. It looks like this:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\010103000F0000F0010000000F0000F0C967A3643C3AD745950DA7859209176EF5B87C875FA20DF21951640E807D7C24]
"Category"=dword:00000001

As I said: the registry keys don’t exist by default. Creating them manually is difficult because of the long number Microsoft chose to use, so it was either the Policy Editor or the .reg file for me. I took the Policy Editor approach but later verified that it created the registry entry shown above, so it’s probably safe to just use the .reg file.

 Posted by on 2016-10-28 at 12:12

Problem accessing a Windows XP share from a Windows 7 PC

 Windows, Windows 7  Comments Off on Problem accessing a Windows XP share from a Windows 7 PC
Mar 092016
 

Today a problem drove me crazy: I tried to map a share on a PC running Windows XP from another computer running Windows 7. I kept getting the error that the username or password are invalid. On the other hand, accessing a share on the Windows 7 PC from the Windows XP PC worked fine. I could also use Remote Desktop on the Windows 7 PC to access the Windows XP PC so I know the credentials were fine.

It turned out that the cause for this was the system time of these two computers being off by more than an hour. Adjusting the time solved the problem for me.

 Posted by on 2016-03-09 at 15:51

Windows annoyance number 3 gazillion and 4

 Windows, Windows 7  Comments Off on Windows annoyance number 3 gazillion and 4
Apr 082015
 

We all know, that Microsoft software is great and that they are constantly striving to improve the user experience (best example: Windows 8 (Yes, that’s sarcasm)).

Windows 7, the best Windows of all times, has a great feature which is an improvement of the universally loved desktop cleanup we know from Windows XP. It regularly helps us to get rid of broken and unused shortcuts on the desktop, which are a serious scourge for humanity. To be even more helpful, it doesn’t ask you but just does its task. And to add to its usefulness, you can’t disable it (Yes, more sarcasm.).

This lead to my coworkers complaining that they lose all their icons on the desktop around every 4 weeks. Some of them accept it, restore them and live with the conveniences of the great Windows 7. Others call me and ask me what to do.

There is an entry in the Microsoft Knowledgebase about this feature.

What it says is basically this:

  • It’s not a bug, it’s a feature.
  • There is a hotfix for it, which you can request by email only
  • Once you have installed that hotfix, you can run a Fixit tool that changes two registry entries.

Unfortunately I can’t provide the hotfix downloads (there are two different ones, one for 32 bit Windows 7 and one for 64 bit Windows 7). The files are called Windows6.1-KB2642357-x64.msu and Windows6.1-KB2642357-x86.msu respectively.

What I can do, is provide you with a .reg file that changes those two registry entries. This will only work after you have applied the hotfix!.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\ScheduledDiagnostics]
"EnabledExecution"=dword:00000001
"IsBrokenShortcutsTSEnabled"=dword:00000000
"IsUnusedDesktopIconsTSEnabled"=dword:00000000

Put this into a text file, change its extension to .reg and open it on the computer that has the problem.

It worked for me. If it doesn’t work for you, don’t blame me, praise Microsoft.

 Posted by on 2015-04-08 at 10:54

Windows 7 Blue Screen Of Death with error 0x7B

 Windows, Windows 7  Comments Off on Windows 7 Blue Screen Of Death with error 0x7B
Aug 132014
 

If you ever had to change the motherboard of your computer and wanted to keep the Windows installation on it, you might have encountered the dreaded Blue Screen of Death with an unhelpful error code.

In my case, this was a Windows 7 installation where the on board SATA controller started to misbehave. These problems didn’t show up in Windows but only when I did my weekly backup using CloneZilla. I wonder what would have happened if I had happily continued to use this computer because Windows didn’t warn me?

First I put the hard disk into a different computer, started CloneZilla and made a backup. No errors showed up, so it wasn’t the hard disk but the controller.

Then I threw out the old motherboard and took a new (cheap) one that still supported my old Dual Core processor and RAM. Connected everything and booted the box. I was expecting for it just to work. This is Windows 7, one of the most modern operating systems available, so driver issues should be a thing of the past, right?

Well, not so. Windows 7 crashed and rebooted, crashed and rebooted, crashed and rebooted. After a while I got tired of this 😉 , pressed F8 for the boot menu and disabled automatic reboot on errors. Then I got the BSOD in all it’s glory: Error code 0x7B, meaning “INACCESSIBLE_BOOT_DEVICE”.

In the olden (Windows XP) days this was a symptom of the SATA controller running in AHCI mode and Windows expecting IDE mode or vice versa. Apparently this is still the same with Windows 7 (When will you ever learn, Microsoft?).

Unfortunately the new board’s BIOS did not really allow me to switch the SATA mode (it seemed to allow me, but it didn’t make any difference). So after swearing a lot I turned to Google and found … a lot, most of it not really helpful. Hours (literally!) later, the solution turned out to be the following:

To allow Windows 7 to boot in IDE as well as AHCI mode, I had to enable the following drivers (by setting “Start” to “0” in the registry, there might be other options to do this):

HKLM\System\CurrentControlSet\services\intelide
HKLM\System\CurrentControlSet\services\pciide
HKLM\System\CurrentControlSet\services\msahci
HKLM\System\CurrentControlSet\services\iastorV

The first two allow Windows 7 to boot from SATA in IDE mode. The second two allow Windows 7 to boot from SATA in AHCI mode.

So, why isn’t that the default? I have no idea.
(Do I have to point out that Linux booted on the updated box without any problems? Which one is the more user friendly system?)

 Posted by on 2014-08-13 at 16:45