PDA

View Full Version : Setting wallpaper on windows



ihoss
10th June 2008, 02:06
I've googled around a bit to try to find out how to set the desktop background in windows. The following is code that looks like it should work, but for some reason it won't.

#include "wallpapr.h"
#include <QSettings>
#include <QVariant>
#ifdef WIN32
#include <windows.h>


Wallpapr::Wallpapr(QWidget *parent)
: QDialog(parent)
{
//ui.setupUi(this);

// String *path = "C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp";
QString *path = new QString("C:\\Documents and Settings\\Marius\\Local Settings\\Application Data\\Microsoft\\Wallpaper1.bmp");
//C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
QSettings *settings = new QSettings("HKEY_CURRENT_USER\\Control Panel\\Desktop",
QSettings::NativeFormat);
//ui.oldWallpaper->setText(settings->value("Wallpaper").toString());
settings->setValue("Wallpaper", QVariant(*path));//"C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
//settings->setValue("ConvertedWallpaper", QVariant(*path));//"C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
//settings->setValue("OriginalWallpaper", QVariant(*path));//"C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
//ui.tempWallpaper->setText(settings->value("Wallpaper").toString());
SystemParametersInfo(SPI_SETDESKWALLPAPER, 1, path, SPIF_SENDWININICHANGE);
//ui.newWallpaper->setText(settings->value("Wallpaper").toString());

}

Wallpapr::~Wallpapr()
{

}
#endif

It changes the registry values, but only removes the current wallpaper. The desktop is a clear color after running the program.

Anyone know how I could make it work?

wysota
10th June 2008, 07:41
I doubt the WinAPI function takes a pointer to a QString. Are you sure this is correct?

ihoss
10th June 2008, 12:56
Well, it needs a pointer at least. And I thought QString was a subclass of String anyways.

edit: I tried with a char pointer instead, but it didn't work either.


#ifdef WIN32
#include <windows.h>


Wallpapr::Wallpapr(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
char *path = "C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp";
// QString *path = new QString("C:\\Documents and Settings\\Marius\\Local Settings\\Application Data\\Microsoft\\Wallpaper1.bmp");
//C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
QSettings *settings = new QSettings("HKEY_CURRENT_USER\\Control Panel\\Desktop",
QSettings::NativeFormat);
//ui.oldWallpaper->setText(settings->value("Wallpaper").toString());
settings->setValue("Wallpaper", QString(path));//"C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
//settings->setValue("ConvertedWallpaper", QString(path));//"C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
//settings->setValue("OriginalWallpaper", QVariant(*path));//"C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
//ui.tempWallpaper->setText(settings->value("Wallpaper").toString());
SystemParametersInfo(SPI_SETDESKWALLPAPER, 1, path, 0);//SPIF_SENDWININICHANGE);
//ui.newWallpaper->setText(settings->value("Wallpaper").toString());

}

Wallpapr::~Wallpapr()
{

}
#endif






[Second edit] Is there a way to run a dll file from a qt program? According to this article (http://windowsitpro.com/article/articleid/93152/how-can-a-batch-script-alter-the-users-screen-saver-and-wallpaper-settings-and-become-effective-without-a-logoff-and-logon.html) there is a way to do it in a batch file. That means it should be a way to do it in c++ too.

wysota
10th June 2008, 14:00
Well, it needs a pointer at least.
But probably not any pointer. Did you read the function's docs at msdn?


And I thought QString was a subclass of String anyways.
You were wrong. And char* is not a subclass of String as well (nor the other way round).

ihoss
10th June 2008, 15:04
I tried making a string from the char pointer. It doesn't change the current wallpaper, but it doesn't remove the previous one either. The function returns false. But if I set the second parameter to NULL it returns true. Nothing happens on the desktop though.



#include "wallpapr.h"
#include <QSettings>
#include <QVariant>
#include <QDirModel>
#include <QFileDialog>
#include <QPixmap>
#include <iostream>
#include <stdio.h>
#include <string>
#ifdef WIN32
//#include <winuser.h>
#include <Windows.h>

using namespace std;

Wallpapr::Wallpapr(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
char *path = "C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp";
// QString *path = new QString("C:\\Documents and Settings\\Marius\\Local Settings\\Application Data\\Microsoft\\Wallpaper1.bmp");
//C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
QSettings *settings = new QSettings(WALLPAPER, //"HKEY_CURRENT_USER\\Control Panel\\Desktop",
QSettings::NativeFormat);
//ui.oldWallpaper->setText(settings->value("Wallpaper").toString());
settings->setValue("Wallpaper", QString(path));//"C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
settings->setValue("ConvertedWallpaper", QString(path));//"C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
settings->setValue("OriginalWallpaper", QString(path));//"C:\\Documents and Settings\\All Users\\Documents\\My Pictures\\Sample Pictures\\Sunset.bmp");
//ui.tempWallpaper->setText(settings->value("Wallpaper").toString());
string *pathStr // = new string();
= new string(path);
//string *wp = new string();
//SystemParametersInfo(SPI_GETDESKWALLPAPER, 100, wp, 0);
//qdebug()<<wp;
bool ret = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,
pathStr,
//NULL,
//0);
//SPIF_SENDCHANGE);
//SPIF_SENDWININICHANGE);
SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
ui.newWallpaper->setText(ret ? "true" : "false");


}

Wallpapr::~Wallpapr()
{

}
#endif

wysota
10th June 2008, 15:18
Did you read the function's description at msdn?

ihoss
10th June 2008, 15:25
Yup, if this (http://msdn.microsoft.com/en-us/library/ms724947(VS.85).aspx) is what you mean.

Here is a list of the information I have found about setting the wallpaper:
http://www.codeguru.com/forum/archive/index.php/t-415808.html
http://www.gamedev.net/community/forums/topic.asp?topic_id=365096
http://blogs.msdn.com/coding4fun/archive/2006/10/31/912569.aspx
http://www.chami.com/tips/delphi/111696d.html
http://windowsitpro.com/article/articleid/74578/jsi-tip-3259-windows-2000-wallpaper-policy.html

Most of them also have links to other useful articles. But I stil can't get it to work.

wysota
10th June 2008, 15:39
But have you identified your problem? Does the registry change when you use the function or not? If you relogin, do you see the old or the new wallpaper?

ihoss
10th June 2008, 20:48
Calling the function alone seems to have no effect; it doesn't change the current wallpaper, nor the wallpaper when I log off and log on again. The function also returns false. Changing the registry files only changes the wallpaper when I log off and log on again, but not immediately.


I tried adding this to see what error I got, but all it returned was T.


char* str = NULL; // function allocates the mem with LocalAlloc(), used with LocalFree()
int msg_ret = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | // let the function alloc string mem
FORMAT_MESSAGE_FROM_SYSTEM | // use system message and not a passed one
FORMAT_MESSAGE_IGNORE_INSERTS, // ignore and "inserts"
NULL,
GetLastError(), // get the error
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(WCHAR*)&str,
0,
NULL);
printf("The error is: %s", str);

ihoss
10th June 2008, 21:37
Ok, I took a few steps back and made a single c++ file that only changes the wallpaper, no GUI.



#include <iostream>
#include <stdio.h>
#include <string>
#include <Windows.h>
using namespace std;

int main () {
char *path = "C:\\WINDOWS\\Web\\Wallpaper\\Windows XP.jpg";
string *pathStr = new string(path);
bool ret = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,
pathStr,
//NULL,
//0);
//SPIF_SENDCHANGE);
//SPIF_SENDWININICHANGE);
SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
cout<<"the function returned "<<(ret ? "true" : "false");
char* str = NULL; // function allocates the mem with LocalAlloc(), used with LocalFree()
int msg_ret = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | // let the function alloc string mem
FORMAT_MESSAGE_FROM_SYSTEM | // use system message and not a passed one
FORMAT_MESSAGE_IGNORE_INSERTS, // ignore and "inserts"
NULL,
GetLastError(), // get the error
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(CHAR*)&str,
0,
NULL);
cout<<"\n"<<str;
cout<<"\n"<<path;
return 0;
}

at it returns


the function returned false
The system cannot find the file specified.

C:\WINDOWS\Web\Wallpaper\Windows XP.jpg

But the file exists. I have also tried with bmp files, getting the same error message.

wysota
10th June 2008, 21:50
As far as I know you can't set jpeg files as wallpapers this way. But if it doesn't work with BMP files, then something else has to be wrong. Try a simpler path such as C:\xyz.bmp

ihoss
10th June 2008, 21:58
Nope, not C:\Bliss.bmp or Bliss.bmp in the same folder. It could be that the functon expects something else than a char pointer.

wysota
10th June 2008, 22:07
It might require a wchar pointer. I suggest using this function first to query for the existing wallpaper. This way you'll be able to see how the path is stored in the buffer you provide.

ihoss
10th June 2008, 22:29
#include <iostream>
#include <stdio.h>
#include <string>
#include <Windows.h>
using namespace std;

int main () {
char *path = "C:\\Bliss.bmp";
bool ret = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,
path,
//NULL,
//0);
//SPIF_SENDCHANGE);
//SPIF_SENDWININICHANGE);
SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
cout<<"the function returned "<<(ret ? "true" : "false");
char* str = NULL; // function allocates the mem with LocalAlloc(), used with LocalFree()
int msg_ret = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | // let the function alloc string mem
FORMAT_MESSAGE_FROM_SYSTEM | // use system message and not a passed one
FORMAT_MESSAGE_IGNORE_INSERTS, // ignore and "inserts"
NULL,
GetLastError(), // get the error
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(CHAR*)&str,
0,
NULL);
cout<<"\n"<<str;
cout<<"\n"<<path;
return 0;
}

That code actually works! Great!

But it does not work in QT.

wysota
10th June 2008, 23:15
What do you mean "in Qt"? There is no "in Qt" :) The only problem that might arise is that some macro is included that influences the behaviour of something else, but this is not really a problem with Qt. Reordering includes might help in such situation.

ihoss
11th June 2008, 00:19
Well, it works in its own little cpp file, but when I try to include it in the QT project, it won't work. I have tried to rearrange the includes, but it has no effects. I've also set the namespace to std, but it does not seem to be required to make the little cpp compile.

edit: There is one strange thing though. In the little cpp i have to use CHAR as the 5th argument in the FormatMessage function, but in the "qt" program i have to use WCHAR. That is kinda strange when I include the same files and compile it with the same compiler.

ihoss
11th June 2008, 14:34
I tried to include the little cpp in the main project and just call the function from the application. It didn't work. I've also made sure both are compiled with mingw, and it only works when it is on its own.

ChristianEhrlicher
11th June 2008, 15:36
Use SystemParametersInfoA or convert your QString properly to a WCHAR array with QString::utf16().

ihoss
11th June 2008, 16:02
Wow, adding that A fixed the problem! Thanks a lot Christian. Thanks also to wysota for keeping dialog going :p

IGHOR
18th September 2009, 02:54
Use SystemParametersInfoA or convert your QString properly to a WCHAR array with QString::utf16().

Thank's for this!
IT work's:
QString screenPath="C:\\screen.bmp";
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (PVOID)screenPath.utf16(), SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE)