0

I found this code here

import java.util.HashMap;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIFunctionMapper;
import com.sun.jna.win32.W32APITypeMapper;

public class test {

 public static void main(String[] args) {
      //supply your own path instead of using this one
     String png = "C:\\Overwatch\\690653.png";
     String jpg = "C:\\Witcher\\616521.jpg";
     String path = png;

     System.out.println(SPI.INSTANCE.SystemParametersInfo(
             new UINT_PTR(SPI.SPI_SETDESKWALLPAPER), 
             new UINT_PTR(0), 
             path, 
             new UINT_PTR(SPI.SPIF_UPDATEINIFILE | SPI.SPIF_SENDWININICHANGE)));
   }

   public interface SPI extends StdCallLibrary {

      //from MSDN article
      long SPI_SETDESKWALLPAPER = 20;
      long SPIF_UPDATEINIFILE = 0x01;
      long SPIF_SENDWININICHANGE = 0x02;

      SPI INSTANCE = (SPI) Native.loadLibrary("user32", SPI.class, new HashMap<Object, Object>() {
         {
            put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
            put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
         }
      });

      boolean SystemParametersInfo(
          UINT_PTR uiAction,
          UINT_PTR uiParam,
          String pvParam,
          UINT_PTR fWinIni
        );
    }
}

but it doesn't seem to work with png. I can only use it to set the wallpaper to jpg. I have been having trouble figuring out what UINT_PTR is doing and I'm wondering if I need to change one of them depending on the image type.

I tried changing to UINT and using LPWSTR but it's still only changing to jpg. This is what I currently have...

 public static void main(String[] args){
     String[] paths = {
             "C:\\Overwatch\\690653.png",
             "C:\\Witcher\\616521.jpg",
             "C:\\wallpapers\\mario.gif",
             "C:\\wallpapers\\Mystic_Tree.wmv"
     };

     for(String path : paths)
         System.out.println(change(path) ? "Worked!\n" + path : "Didn't work :(\n" + path);
 }

 public static interface User32 extends StdCallLibrary {
     User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.UNICODE_OPTIONS);        
     boolean SystemParametersInfo (UINT uiAction, UINT uint, Pointer imagePath, UINT fWinIni);         
 }

 public static boolean change(String path){
     Pointer imagePath = new LPWSTR(path).getPointer();

     UINT uiAction = new UINT(0x0014l);
     UINT userPolicy = new UINT(0l);
     long updateIni = 0x01l;
     long sendChange = 0x02l;
     return User32.INSTANCE.SystemParametersInfo(uiAction, userPolicy, imagePath , new UINT(updateIni | sendChange));
 }
Jaek Sean
  • 1
  • 1

1 Answers1

0

There are a few problems with the JNA code, to try to answer your questions about what settings should be used.

First, refer to the method signature for SystemParametersInfo. This should help answer many of your questions.

Note three of the arguments are a UINT (32-bit integer). You should use JNA's UINT (32 bit backed by a long), not a UINT_PTR which can be 32 bit or 64 bit (whatever Pointer.SIZE evaluates to). Although in this particular case you could just pass plain Java int values and get the result you wanted, since none of them are large enough to care about the sign bit.

(Aside, why did you use decimal 20 rather than hex 0x0014? Won't break things, but when doing bitwise math it's clearer to the reader to keep code in hex.)

Note the argument for the string is actually a pointer, and while the documentation I linked to doesn't make it clear, digging around it appears that C is expecting a pointer to a wide character string type here, LPWSTR. You should use something like:

WTypes.LPWSTR png = new WTypes.LPWSTR("C:\\Overwatch\\690653.png");

All that said...

It appears from reading elsewhere that Windows 7 has some shortcomings with regard to wallpapers and image compression that are a bug/feature/design of Windows 7 and may not be a problem with your code. Among these:

  • One of the answers to this question (which may be your original source?) states that "Windows 7 doesn't like setting jpeg images as a wallpaper. You need to convert the image file to Bitmap first and then set the bmp image as background."

  • This thread on Microsoft's site discusses compression issues and suggests "Save your images as a bitmap, aka .bmp and then rename to .jpg so the file itself is actually a bitmap but it gets passed to the OS as a jpeg, so it thinks it doesn't have to compress it"

I would suggest starting with a .bmp and saving it as all the different extensions to rule out any extension-specific behavior.

Community
  • 1
  • 1
Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
  • I tried your improvements on the code above, then I shortened the code and made it loop through multiple file types that I can set my wallpaper to, but it still only works for jpg. Do you have any more ideas as to why it still isn't setting to other file types? When I first implemented your suggestions it was with the first code and all my Strings were LPWSTR. – Jaek Sean Aug 08 '16 at 02:45
  • I believe Windows uses different compression settings for PNG and JPG (the latter isn't compressed.) Have you tried a different PNG file to rule out anything unique with that particular file? Does it work using normal Windows routines? Can you change the size of it? – Daniel Widdis Aug 08 '16 at 16:05
  • I haven't tried other png files but I can set all those files in the stratégie manually by right clicking and choosing "Set as desktop background" or whatever. I work on an oil rig so when I get home in a few days I will grab a bunch of png files of different sizes and try them out. – Jaek Sean Aug 09 '16 at 22:46