diff --git a/CHANGES.md b/CHANGES.md index 8ed38bf40f..81c35ced15 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,9 +10,10 @@ Features * [#1336](https://github.com/java-native-access/jna/pull/1336): Add `HKEY_CURRENT_USER_LOCAL_SETTINGS` to `c.s.j.p.win32.WinReg` - [@Dani-Hub](https://github.com/Dani-Hub). * [#1337](https://github.com/java-native-access/jna/pull/1337): Add `REG_NOTIFY_THREAD_AGNOSTIC` to `c.s.j.p.win32.WinNet` and update `REG_LEGAL_CHANGE_FILTER` - [@Dani-Hub](https://github.com/Dani-Hub). * [#1338](https://github.com/java-native-access/jna/pull/1338): Add `RegNotifyChangeKeyValue` to `c.s.j.p.win32.Advapi32` - [@Dani-Hub](https://github.com/Dani-Hub). -* [#1340](https://github.com/java-native-access/jna/issues/1340): Added `CM_Get_DevNode_Registry_Property` to `c.s.j.p.win32.Cfgmgr32` and corresponding util in `c.s.j.p.win32.Cfgmgr32Util` - [@dbwiddis](https://github.com/dbwiddis). +* [#1340](https://github.com/java-native-access/jna/issues/1340): Add `CM_Get_DevNode_Registry_Property` to `c.s.j.p.win32.Cfgmgr32` and corresponding util in `c.s.j.p.win32.Cfgmgr32Util` - [@dbwiddis](https://github.com/dbwiddis). * [#1352](https://github.com/java-native-access/jna/pull/1352): Add `BringWindowToTop` to `c.s.j.p.win32.User32` - [@kahgoh](https://github.com/kahgoh). * [#1354](https://github.com/java-native-access/jna/pull/1352): Add `GetParent` to `c.s.j.p.win32.User32` - [@kahgoh](https://github.com/kahgoh). +* [#1360](https://github.com/java-native-access/jna/issues/1360): Add `CommandLineToArgvW` to `c.s.j.p.win32.Shell32` and corresponding util in `c.s.j.p.win32.Shell32Util` - [@dbwiddis](https://github.com/dbwiddis). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java b/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java index a52812be03..22d96b5260 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java @@ -24,8 +24,10 @@ package com.sun.jna.platform.win32; import com.sun.jna.Native; +import com.sun.jna.Pointer; import com.sun.jna.WString; import com.sun.jna.platform.win32.Guid.GUID; +import com.sun.jna.platform.win32.WTypes.LPWSTR; import com.sun.jna.platform.win32.WinDef.DWORD; import com.sun.jna.platform.win32.WinDef.HICON; import com.sun.jna.platform.win32.WinDef.HWND; @@ -33,6 +35,7 @@ import com.sun.jna.platform.win32.WinDef.UINT_PTR; import com.sun.jna.platform.win32.WinNT.HANDLE; import com.sun.jna.platform.win32.WinNT.HRESULT; +import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; import com.sun.jna.win32.StdCallLibrary; import com.sun.jna.win32.W32APIOptions; @@ -409,5 +412,28 @@ public interface Shell32 extends ShellAPI, StdCallLibrary { */ HRESULT SetCurrentProcessExplicitAppUserModelID(WString appID); + /** + * Parses a Unicode command line string and returns an array of pointers to the + * command line arguments, along with a count of such arguments, in a way that + * is similar to the standard C run-time {@code argv} and {@code argc} values. + * + * @param lpCmdLine + * A Unicode string that contains the full command line. If this + * parameter is an empty string the function returns the path to the + * current executable file. + * @param pNumArgs + * Pointer to an {@code int} that receives the number of array + * elements returned, similar to {@code argc}. + * @return A pointer to an array of {@link LPWSTR} values, similar to + * {@code argv}. If the function fails, the return value is + * {@code null}. To get extended error information, call + * {@link Kernel32#GetLastError}.
+ * CommandLineToArgvW allocates a block of contiguous memory for + * pointers to the argument strings, and for the argument strings + * themselves; the calling application must free the memory used by the + * argument list when it is no longer needed. To free the memory, use a + * single call to the {@link Kernel32#LocalFree} function. + */ + Pointer CommandLineToArgvW(WString lpCmdLine, IntByReference pNumArgs); } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java index b33163235f..a177394833 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java @@ -24,11 +24,14 @@ package com.sun.jna.platform.win32; import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.WString; import com.sun.jna.platform.win32.Guid.GUID; import com.sun.jna.platform.win32.WinDef.DWORD; import com.sun.jna.platform.win32.WinDef.HWND; import com.sun.jna.platform.win32.WinNT.HANDLE; import com.sun.jna.platform.win32.WinNT.HRESULT; +import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; /** @@ -112,4 +115,28 @@ public static final String getSpecialFolderPath(final int csidl, final boolean c throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); return Native.toString(pszPath); } + + /** + * Parses a command line string and returns an array of Strings of the command + * line arguments. + * + * @param cmdLine + * A string that contains the full command line. If this parameter is + * an empty string the function returns the path to the current + * executable file. + * @return An array of strings, similar to {@code argv}. + */ + public static final String[] CommandLineToArgv(String cmdLine) { + WString cl = new WString(cmdLine); + IntByReference nargs = new IntByReference(); + Pointer strArr = Shell32.INSTANCE.CommandLineToArgvW(cl, nargs); + if (strArr != null) { + try { + return strArr.getWideStringArray(0, nargs.getValue()); + } finally { + Kernel32.INSTANCE.LocalFree(strArr); + } + } + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } } \ No newline at end of file diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java index c88e2b5aee..a46c22ae66 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java @@ -23,11 +23,14 @@ */ package com.sun.jna.platform.win32; +import static org.junit.Assert.assertArrayEquals; + import java.io.File; import java.io.FileWriter; import java.io.IOException; import com.sun.jna.Native; +import com.sun.jna.Pointer; import com.sun.jna.WString; import com.sun.jna.platform.win32.Guid.GUID; import com.sun.jna.platform.win32.ShellAPI.APPBARDATA; @@ -36,11 +39,11 @@ import com.sun.jna.platform.win32.WinDef.UINT_PTR; import com.sun.jna.platform.win32.WinNT.HANDLE; import com.sun.jna.platform.win32.WinNT.HRESULT; +import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; import junit.framework.TestCase; - /** * @author dblock[at]dblock[dot]org * @author markus[at]headcrashing[dot]eu @@ -260,4 +263,16 @@ public void testCurrentProcessExplicitAppUserModelID() { Ole32.INSTANCE.CoTaskMemFree(ppszAppID.getValue()); } + public void testCommandLineToArgvW() { + WString cl = new WString("\"foo bar\" baz"); + String[] argv = { "foo bar", "baz" }; + IntByReference nargs = new IntByReference(); + Pointer strArr = Shell32.INSTANCE.CommandLineToArgvW(cl, nargs); + assertNotNull(strArr); + try { + assertArrayEquals(argv, strArr.getWideStringArray(0, nargs.getValue())); + } finally { + Kernel32.INSTANCE.LocalFree(strArr); + } + } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java index 410a6dfc95..c7245191f8 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java @@ -23,6 +23,8 @@ */ package com.sun.jna.platform.win32; +import static org.junit.Assert.assertArrayEquals; + import junit.framework.TestCase; /** @@ -85,4 +87,10 @@ public void testGetKnownFolderPath() // assertNotNull(Shell32Util.getKnownFolderPath(KnownFolders.FOLDERID_UserProgramFiles)); // assertNotNull(Shell32Util.getKnownFolderPath(KnownFolders.FOLDERID_UserProgramFilesCommon)); } + + public void testCommandLineToArgv() { + String cl = "\"foo bar\" baz"; + String[] argv = { "foo bar", "baz" }; + assertArrayEquals(argv, Shell32Util.CommandLineToArgv(cl)); + } }