Setting Wallpaper

Hello! I'm creating a basic program to change my desktop wallpaper via a random seed and SystemParametersInfo() and I'm having some issues. The function appears to execute without error, yet it does not reset my background. Any thoughts?

I have made one interesting observation. Sometimes it will reset the background to black, and other times it will simply keep the previous background. I've also experimented with other formats other than .jpg and that makes no difference.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <windows.h>
#include <iostream>
#include <shlobj.h>
#include <time.h>
#include <cstdlib>
#include <stdio.h>
#include <string>
#include <sstream>

using namespace std;

bool setBackground();
LPWSTR ConvertToLPWSTR( const std::string &s );

string strLocalDirectory = "C:\\Users\\Mezmiro\\Desktop\\Wallpapers\\";
stringstream ssFilePath;
LPWSTR lpFilePath;  //Final resting place for full pathname. 
DWORD DWLastError;

int main(int argc, char *argv[])
{ 
  if(setBackground()) { 
    cout << "Applied Background: " << ssFilePath.str() << "\n";
  }
  else {  
     DWLastError = GetLastError();
    cout << "\nError: " << std::hex << DWLastError;
  } 
  delete[] lpFilePath; // Clean up before exit. 
  cin.get();
 return EXIT_SUCCESS;
}

bool setBackground()
{
  int dirSize = 5;  //Will be automated later. 
  int bgChoice = 0; //Index of chosen wallpaper. 
  
  srand ( time(NULL) );
   bgChoice = rand() % dirSize + 1;
  //Convert the index choice into a usable filename string.
  ssFilePath << strLocalDirectory << bgChoice << ".jpg";
  ConvertToLPWSTR( ssFilePath.str() );
  //Returns true on success, false otherwise. 
  if( SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, lpFilePath, SPIF_UPDATEINIFILE) != 0)
  {
    // Refresh the desktop:
    LPITEMIDLIST pidl;
    SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&pidl);
    SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,pidl,0);
    return true;
  }
  else
    return false;
}

LPWSTR ConvertToLPWSTR( const string &s )
{
  LPWSTR newWSTR = new wchar_t[s.size()+1]; //+1 for termination character.
  copy( s.begin(), s.end(), newWSTR );
  newWSTR[s.size()] = 0; // Terminate the string. 
  return newWSTR;
}
Last edited on
Did you try refreshing the desktop?
Yeah I did it manually before and it didn't work. I inserted some code to do it in the program just now, but the same result appears. No wallpaper change!

Is there some other process I'm forgetting about? This box is on Vista SP1.
Last edited on
Well...

1. lpFilePath isn't being set to anything

(Is line 43 supposed to be

lpFilePath = ConvertToLPWSTR( ssFilePath.str() );

i.e. the return from ConvertToLPWSTR be used to set something?)

2. that's not the way to convert an ANSI string to Unicode.

Use MultiByteToWideChar

3. Do you need to convert to Unicode anyway? Try passing string to ANSI version of function?

SystemParametersInfoA

4. if you do use SHGetSpecialFolderLocation, you need to free the returned PIDL with CoTaskMemFree (you were careful enough to delete lpFilePath...)

5. using the SPIF_SENDCHANGE flag with SystemParametersInfo makes more sense here (than using SHChangeNotify)

Andy

This works for me!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <windows.h>
#include <iostream>
#include <shlobj.h>
#include <time.h>
#include <cstdlib>
#include <string>
#include <sstream>

using namespace std;

bool setBackground();

const string strLocalDirectory = "C:\\Test\\Wallpapers\\"; // TWEAKED PATH

string filePath;

int main() // so no warnings about unref params
{ 
  if(setBackground()) { 
    cout << "Applied Background: " << filePath << "\n";
  } else {  
     DWORD DWLastError = GetLastError();
     cout << "\nError: " << std::hex << DWLastError;
  } 
  cin.get();
  return EXIT_SUCCESS;
}

bool setBackground()
{
  int dirSize = 5;  //Will be automated later. 
  int bgChoice = 0; //Index of chosen wallpaper. 
  
  srand ( (unsigned int)time(NULL) );
  bgChoice = rand() % dirSize + 1;
  //Convert the index choice into a usable filename string.
  stringstream ssFilePath;
  ssFilePath << strLocalDirectory << bgChoice << ".jpg";
  //Returns true on success, false otherwise. 
  if( SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, (PVOID)ssFilePath.str().c_str(),
                            SPIF_UPDATEINIFILE | SPIF_SENDCHANGE) != 0)
  {
    filePath = ssFilePath.str();
    return true;
  }

  return false;
}
Last edited on
Excellent, thank you! It certainly works now. And I have a few more things to research. :)

I had no idea you could use SystemParametersInfoA() anymore. The references I found online regarded it as a legacy function which didn't support .jpg's, which I thought to be a little strange.
The MSDN entry for SystemParametersInfo makes not comments about limitations of SystemParametersInfoA. Like all (or at least most) -A functions, it no doubt just converts all strings from ANSI to Unicode and then calls the corresponding -W function.

You could convert your code to work with Unicode literals, wstring, wstringstream (or better, wostringstream), etc. and the -W versions of the functions.

Andy
Last edited on
PS This might be of interest

Why does SystemParametersInfo hang when I pass the SPIF_SENDCHANGE flag?
http://blogs.msdn.com/b/oldnewthing/archive/2005/03/10/392118.aspx

Andy
For this application I think I'll just stick to the (PVOID) cast of the c_str() since I'm only developing this for personal use. Though if I do decide to utilize Unicode functions, that's very good to know!

Though one thing does worry me a bit. It appears my linker does not like CoTaskMemFree(pidl), which is a little odd. I have included windows.h, which should also include Objbase.h. Which library would I need to link to in order to utilize this function? I'm currently using Dev-C++ 4.9.9.2.

 
[Linker error] undefined reference to `CoTaskMemFree@4'  
Are you linking to Ole32.lib ?? (or rather, libole32.a if your build with GCC)

Andy
Last edited on
Nope! Though I will once I reinstall Dev-C++. It appears, accessing the project options makes the entire IDE crash now.. interesting. I reinstalled/updated and everything appears to be working fine now.

Thanks anyways! Now to bury my head into some more code..
Topic archived. No new replies allowed.