0
votes

I copied code that's supposed to change desktop wallpaper. I have this constant in my program:

const char * image_name = "button_out.gif";

Later, I write the image on disk using Magick++:

image.write(image_name);

The image appears in program's working directory. If I run the program directly from explorer the working directory equals the program location.

image and the image generator

Because the code prints the 0x80070002 - File not found error I added a exist function in the beginning:

#include <sys/stat.h>
bool exists(const char* name) {
  struct stat buffer;   
  return (stat (name, &buffer) == 0); 
}
void  SetWallpaper(LPCWSTR file){
  if(!exists((const char* )file)) {
    wcout << "The file "<<file<<" does not exist!" << endl;  
  return;
  ... actually try to set a wallpaper ...
}

The error is not printed however and the code proceeds.

Now the question is:

  1. Does my exist function work properly?
  2. Where does windows look for that image?

Full code to set a Magick++ generated image as background in case I have missed something relevant in this question.

1

1 Answers

5
votes

Problem 1: String Conversions

Your primary problem is that you are attempting to use LPCWSTR (a const wchar_t *) and const char * interchangeably. I see a number of issues in your source, in particular:

  • You start with const char * image_name.
  • You then cast it to a LPCWSTR to pass to SetWallpaper. This basically guarantees that SetWallpaper will fail, as desktop->SetWallpaper is not able to handle non wide-character strings.
  • You then cast it back to a const char * to pass to stat() via exists(). This should work in your situation (since the original string really is a char *) but isn't correct because your string parameter to SetWallpaper is supposedly a proper LPCWSTR.

You need to pick a string format (wide-character vs. what Windows terms "ANSI") and stick to that format, using consistent APIs throughout.

The easiest option is probably just to leave most of your code untouched, but modify SetWallpaper to take a const char * and convert to a wide-character string when needed (for this you can use mbstowcs). So, for example:

void  SetWallpaper(const char * file){  // <- Use a const char* parameter.
   ...

   // Convert to a wide-character string to pass to COM: 
   wchar_t wcfile[MAX_PATH + 1];
   mbstowcs(wcfile, file, sizeof(wcfile) / sizeof(wchar_t));

   // Pass the converted wide-character string:
   desktop->SetWallpaper(wcfile, 0);

   ...
}

The other option would be to use wide-character strings throughout, i.e.:

  • LPCWSTR image_name = L"button_out.gif";
  • Modify exists() to take a LPCWSTR and use _wstat() instead.
  • Use wide-character versions of all other API functions.

However, I am unsure how that would interact with the ImageMagick API, which may not have wide-character support. So it's up to you. Choose whatever approach is the easiest to implement but make sure you are consistent. The general rule is do not cast between LPCWSTR and const char *; if you are ever in a situation where you need to change one to the other, you cannot cast, you must convert (via mbstowcs or wcstombs).

Problem 2: SetWallpaper default directory is not current working directory

At this point, your string usage will be consistent. Now that you have that problem ironed out, if SetWallpaper fails while exists() does not, then SetWallpaper is not looking where you think it is. As you discovered in your comment, SetWallpaper looks in the desktop by default. In this case, while I have not tested it, you may be able to work around this by passing an absolute path to SetWallpaper. For this, you can use GetFullPathName to determine the absolute file name given your relative path. Remember to be consistent with your string types, though.

Also, if stat() continues to fail, then that problem is either that your working directory is not what you think it is, or your filename is not what you think it is. To that end you will want to perform the following tests:

  • Print the current working directory at the point you check for the files existence, verify it is correct.
  • Print the filename when you check for its existence, verify it is correct.

You should be good to go once you work all the above issues out.