我可以在Java/Groovy中以编程方式更改我的Windows桌面墙纸吗?

e1xvtsh3  于 2022-11-01  发布在  Java
关注(0)|答案(6)|浏览(148)

有没有办法在Windows XP中使用Java(或Groovy)更改桌面墙纸?我有一个每天(或随时)创建新图像的程序,我希望有一种自动更新桌面的方法。
我在这个站点上看到了一些关于C++或.NET问题,但我没有看到任何特定于Java的问题。

agyaoht7

agyaoht71#

对不起,我有点落后于@ataylor的答案,因为我正在准备一个片段来做这件事。是的,JNA是一个正确的方法。在这里,你去:

import java.util.HashMap;

import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
import com.sun.jna.win32.*;

public class WallpaperChanger {
   public static void main(String[] args) {
      //supply your own path instead of using this one
      String path = "C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg";

      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
        );
  }
}

你需要在类路径上有JNA库才能工作。这是在Windows7中测试的,在XP中可能会有一些细微差别,但我认为它应该工作。那个API应该是稳定的。

参考

编辑(2010年1月20日):
我以前省略了选项SPIF_UPDATEINIFILESPIF_SENDWININICHANGE。现在按照Coding 4Fun MSDN文章中的建议使用这些选项。

rm5edbpk

rm5edbpk2#

你可以做得更容易:

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.PVOID;
import com.sun.jna.win32.W32APIOptions;
public class Wallpaper {    
 public static interface User32 extends Library {
     User32 INSTANCE = (User32) Native.loadLibrary("user32",User32.class,W32APIOptions.DEFAULT_OPTIONS);        
     boolean SystemParametersInfo (int one, int two, String s ,int three);         
 }
public static void main(String[] args) {   
   User32.INSTANCE.SystemParametersInfo(0x0014, 0, "C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg" , 1);
   }
 }
r55awzrz

r55awzrz3#

您可以编写一个batch file to change the wall-paper,并使用以下命令执行该批处理文件:
Runtime.getRuntime.exec()

ocebsuys

ocebsuys4#

JNA java库允许您轻松调用Win32 API调用,特别是要更改桌面背景,需要调用SystemParametersInfo函数。
请参阅这篇文章,了解JNA的简介:http://today.java.net/article/2009/11/11/simplify-native-code-access-jna

bsxbgnwa

bsxbgnwa5#

这是一个纯Java实现,它使用Project Panama将本机回调到Windows USER32.DLL中。请注意,API正在孵化,因此在JDK 16、17和更高版本之间发生了变化。这些示例使用当前JDK 16/17版本中的Panama版本,如果您切换到最新的Panama Early Access版本,则可能需要进行一些更改。

import java.lang.invoke.*;
import java.nio.file.Path;
import jdk.incubator.foreign.*;

/**
 %JDK16%\bin\java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign SetWallpaper.java A.JPG
 */
public class SetWallpaper {
    static final int SPI_SETDESKWALLPAPER  = 0x0014;
    static final int SPIF_UPDATEINIFILE    = 0x01;
    static final int SPIF_SENDCHANGE       = 0x02;
    public static void main(String[] args) throws Throwable {
        LibraryLookup user32 = LibraryLookup.ofLibrary("user32");
        MethodHandle spi = CLinker.getInstance().downcallHandle(user32.lookup("SystemParametersInfoA").get()
            // BOOL SystemParametersInfoA         (UINT uiAction,  UINT uiParam,   PVOID pvParam,       UINT fWinIni);
            , MethodType.methodType(int.class,     int.class,      int.class,      MemoryAddress.class, int.class)
            , FunctionDescriptor.of(CLinker.C_LONG,CLinker.C_LONG, CLinker.C_LONG, CLinker.C_POINTER,   CLinker.C_LONG));

        Path path = Path.of(args[0]).toRealPath();

        try (NativeScope scope = NativeScope.unboundedScope()) {
            MemorySegment img = CLinker.toCString(path.toString(), scope);
            int status = (int)spi.invokeExact(SPI_SETDESKWALLPAPER, 0, img.address(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
            System.out.println("Changed wallpaper to "+path+" rc="+status+(status == 0 ? "***ERROR***": " OK"));
        }
    }
}

JDK 17所需的小改动:

/**
%JAVA_HOME%\bin\java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign SetWallpaper.java A.JPG

* /

public static void main(String[] args) throws Throwable {
    System.loadLibrary("user32");
    // BOOL SystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
    MemoryAddress symbol = SymbolLookup.loaderLookup().lookup("SystemParametersInfoW").get();
    MethodHandle SystemParametersInfoW = CLinker.getInstance().downcallHandle(symbol
        , MethodType.methodType(int.class,     int.class,      int.class,      MemoryAddress.class, int.class)
        , FunctionDescriptor.of(CLinker.C_LONG,CLinker.C_LONG, CLinker.C_LONG, CLinker.C_POINTER,   CLinker.C_LONG));

    Path path = Path.of(args[0]).toRealPath();

    try(ResourceScope scope = ResourceScope.newConfinedScope()) {
        SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
        // toCString as WIDE string
        Addressable wide = allocator.allocateArray(CLinker.C_CHAR, (path+"\0").getBytes(StandardCharsets.UTF_16LE));
        int status = (int)SystemParametersInfoW.invokeExact(SPI_SETDESKWALLPAPER, 0, wide.address(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
        System.out.println("Changed wallpaper to "+path+" rc="+status+(status == 0 ? "***ERROR***": " OK"));
    }
}
x8diyxa7

x8diyxa76#

扩展@DuncG的答案,这里有一个更新的解决方案,它使用JDK 18中的Project Panama。

import jdk.incubator.foreign.*;

import java.lang.invoke.MethodHandle;
import java.nio.file.Path;

import static jdk.incubator.foreign.ValueLayout.*;

public class WindowsOperatingSystem {
    private static final int SPI_SETDESKWALLPAPER  = 0x0014;
    private static final int SPIF_UPDATEINIFILE    = 0x01;
    private static final int SPIF_SENDCHANGE       = 0x02;

    private static final MethodHandle systemParametersInfoAFunction;

    static {
        System.loadLibrary("user32");
        // BOOL SystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
        systemParametersInfoAFunction = CLinker.systemCLinker().downcallHandle(
                SymbolLookup.loaderLookup().lookup("SystemParametersInfoA").get(),
                FunctionDescriptor.of(JAVA_BOOLEAN, JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT)
        );
    }

    public static void setWallpaper(Path file) {
        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            SegmentAllocator allocator = SegmentAllocator.nativeAllocator(scope);
            Addressable nativeFilePath = allocator.allocateUtf8String(file.toString());
            var result = (boolean)systemParametersInfoAFunction.invokeExact(
                    SPI_SETDESKWALLPAPER,
                    0,
                    nativeFilePath,
                    SPIF_UPDATEINIFILE | SPIF_SENDCHANGE
            );
            if (!result) {
                throw new IllegalStateException();
            }
        } catch (Error | RuntimeException t) {
            throw t;
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }
}

相关问题