2

I have created a simple application using Delphi 10.2 Tokyo (using FireMonkey) that displays images and allows you to set the desktop wallpaper for a selected image. The main code that sets the desktop wallpaper is:

class procedure TUtilityWin.SetWallpaper(AFileName: String);
begin
      SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, pChar(AFileName), (SPIF_UPDATEINIFILE OR SPIF_SENDWININICHANGE)); 
end;

While this works great when the application runs on the desktop (as a standalone install), it fails when run as an APPX (during the certification process) of submitting to the Windows 10 App Store. When setting the wallpaper as an APPX, the result is a black screen background instead of the selected image.

I thought that this was due to the APPX running in a constrained mode with access only to a virtual registry (and not the actual registry). So I changed the call to this:

SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, pChar(AFileName), 0); 

This also works when run as a standalone application on the desktop. But even removing the parameter SPIF_UPDATEINIFILE does not get the app to work as an APPX package deployment - it still does not set the wallpaper and results in a black screen.

Would be interested in any guidance from this community about how I can set the desktop wallpaper and have it work even when packaged and deployed as an APPX. Thanks in advance!

Addendum: I am going off this documentation (excerpt below):

fWinIni [in]

Type: UINT

If a system parameter is being set, specifies whether the user profile is to be updated, and if so, whether the WM_SETTINGCHANGE message is to be broadcast to all top-level windows to notify them of the change.

This parameter can be zero if you do not want to update the user profile or broadcast the WM_SETTINGCHANGE message...

UPDATE 20170804:

Based on feedback from @Victoria and @DaveNottage, I took a stab at implementing WinRT calls as follows:

Uses WinAPI.WinRT, WinApi.SystemRT, WinAPI.Storage, WinApi.Foundation.Types;

procedure TForm1.Button1Click(Sender: TObject);
const
  imgfname: String = 'C:\Users\rohit\Pictures\Camera Roll\WIN_20170302_12_12_33_Pro.jpg';
var
  isf_StorageFile: IAsyncOperation_1__IStorageFile;
  sfile: IStorageFile;
begin
  if TUserProfile_UserProfilePersonalizationSettings.IsSupported then
  begin
    isf_StorageFile:=TStorageFile.GetFileFromPathAsync(HSTRING(imgfname));
    isf_StorageFile.Completed:= AsyncOperationCompletedHandler_1__IStorageFile (
                                procedure (sf: IAsyncOperation_1__IStorageFile; status: AsyncStatus)
                                begin
                                  if status=AsyncStatus.Completed then
                                  begin
                                    sFile:=sf.GetResults;
                                    TUserProfile_UserProfilePersonalizationSettings.Current.TrySetWallpaperImageAsync(sFile);
                                  end;
                                end);
  end;
end;

Unfortunately this does not work and gives an error: No such interface supported. Would appreciate it if someone could look over this and let me know what I am doing wrong...

Rohit
  • 909
  • 1
  • 9
  • 20
  • 1
    You should use [UserProfilePersonalizationSettings.TrySetWallpaperImageAsync](https://learn.microsoft.com/en-us/uwp/api/windows.system.userprofile.userprofilepersonalizationsettings) method. – Victoria Aug 04 '17 at 05:42
  • Thanks @Victoria - that seems to be well worth trying. Could you please point me to the Delphi unit that exposes this method? – Rohit Aug 04 '17 at 05:48
  • I'm afraid I cannot, sorry. I don't even know if that class is included in FMX. – Victoria Aug 04 '17 at 06:28
  • It's just a wild guess, but what exactly is the path to the file? Not sure if some magic is involved when it's a file from inside your package. Have you tried something simple like `c:\someFile.bmp` that is definitely from outside your package space? – Günther the Beautiful Aug 04 '17 at 06:49
  • @GünthertheBeautiful - I cache the image file in a folder under %APPDATA% - which is outside of the package space. What I was led to believe is that the APPX is certified in a locked down environment that simulates Windows S so that the change the API call makes is stored in APPX isolated virtual registry (not actual registry) storage. What I don't understand is why this still does not work when I set the last parameter to 0 (i.e. do not write to registry). – Rohit Aug 04 '17 at 06:58
  • You should check the result of `SystemParametersInfo(..)` to find out what's wrong. What do you get if you try to retrieve the wallpaper path after you have set it (by calling `SystemParametersInfo(..)` once again, this time with `SPI_GETDESKWALLPAPER`?) – Günther the Beautiful Aug 04 '17 at 07:07
  • @GünthertheBeautiful - the call to `SPI_SETDESKWALLPAPER` is always successful whenever I run it as a desktop application (i.e. not as an APPX deployment) - the wallpaper on my desktop changes and I get a boolean result of `TRUE`. For some reason (I suspect the virtual registry issue mentioned above) when this is run during APPX certification it does not work. – Rohit Aug 04 '17 at 07:51
  • 1
    @Günther, `SystemParametersInfo` is not supported for Windows Store apps. It would be mentioned in requirements, or listed [here](https://msdn.microsoft.com/en-us/library/windows/apps/dn424765.aspx). What's more, UWP applications are running sandboxed. – Victoria Aug 04 '17 at 08:00
  • 2
    @Rohit The function Victoria referred to is in Winapi.SystemRT. You'll need to use something like: TUserProfile_UserProfilePersonalizationSettings.Current.TrySetWallpaperImageAsync. As to how to obtain an IStorageFile to pass to it, I have no idea at present. – Dave Nottage Aug 04 '17 at 08:34
  • @DaveNottage - thanks for this! I will play around with it a bit to see if I can figure it out... – Rohit Aug 04 '17 at 10:16
  • 1
    You could not get the image file by its path. It's not supported in UWP. Please check [Skip the path: stick to the StorageFile](https://blogs.msdn.microsoft.com/wsdevsol/2012/12/04/skip-the-path-stick-to-the-storagefile/) You could choose to copy image into your app's local folder. Or you could use the [filepicker](https://learn.microsoft.com/en-us/windows/uwp/files/quickstart-using-file-and-folder-pickers) to select a image file and pass the storagefile to the `TryS‌​etWallpaperImageAsyn‌​c` method as its parameter. – Xie Steven Aug 07 '17 at 05:10
  • See https://stackoverflow.com/questions/45633237/delphi-making-asynchronous-calls-to-winrt-api-using-ttask-future/58208687#58208687 – Dmitry Streblechenko Oct 02 '19 at 20:19

0 Answers0